洛谷 P1514 引水入城 题解
这道题经常是作为一个搜索题出现的,但是实际上它还用dp或贪心处理搜索后的结果。
来看这道题,题意很好理解,第一问也很好做(从每个第一行的点开始搜,判断整个第一行在第N行上覆盖的点数量是否等于M就好了)
然而,想到这里还不足以解决第二问。
想要解决第二问首先需要明确一个引理:第一行某个点在第N行上覆盖的点一定是一个区间(这个自己推或看洛谷题解里的证明,实际并不是很难想)
到了这里,问题就转化为了用最少的子区间覆盖全区间的问题。
这个问题有两种方法:dp和贪心,这里我选择的是贪心。
贪心策略:对于全区间的某个点,包含该点且右端点尽量大的子区间是合法且最优的。
注:洛谷上需要一个小优化:如果第一行上的某个点x可以从其他第一行上的点y到达,那么不需要对x点进行搜索(因为路径x集合真包含于路径y集合),代码中mark数组就是完成这个优化的。
#include#include #include #include #define int long long #define maxn 510 #define rep(i,s,e) for(register int i=s;i<=e;++i) #define dwn(i,s,e) for(register int i=s;i>=e;--i) using namespace std; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();} return f*x; } inline void write(int x) { if(x<0){putchar('-');x=-x;} if(x>9)write(x/10); putchar(x%10+'0'); } int n,m; int map[maxn][maxn]; int book[maxn][maxn]; int mark[maxn]; int last_row[maxn]; struct node { int l,r; }s[maxn]; int dx[5]={0,1,-1,0,0}; int dy[5]={0,0,0,1,-1}; bool cmp(node x,node y) { return x.r>y.r; } void dfs(int x,int y) { if(x==n) last_row[y]++; if(x==1) mark[y]=1; book[x][y]=1; rep(i,1,4) { int xx=x+dx[i],yy=y+dy[i]; if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&map[xx][yy]