题目链接:https://vijos.org/p/1777
思路:网上的大神思路写的很清晰了,每个水站覆盖的干旱城市在有解情况下一定是一个区间,否则无解,然后剩下的就是线段覆盖问题啦。
求每个水站覆盖的区间:
用记忆化搜索,设l(i,j),r(i,j)分别表示从(i,j)可以到达的区间左端点和右端点,那么每次Flood fill时遇到已到达的位置就可以直接使用信息,不需要再次进行搜索,这样就将Flood fill的复杂度降到O(nm)。(记忆化使用深搜的话更加方便,实在不行就手写栈吧。。(没开O2的STL实在好慢。。。))
线段覆盖:实在不清楚DP的写法,所以我自己写了一个O(n log n)的贪心,现将线段按照左端点排序,然后设一个数组f(),初始时全为正无穷(除0),f(0)=0,然后扫描线段,每次取区间[l-1,m]中的最小值,设为Fmin,然后更新f(r)为min(f(r),Fmin+1),全部扫描完毕后f(m)即为答案。(用树状数组或线段树优化可以做到O(n log n),建议常数较小的BIT)
复杂度:flood fill O(nm) 线段覆盖O(m log m) 所以总复杂度O(nm+m log m)
速度勉勉强强(vijos):
代码:
#include
#include
#include
#include
using namespace std;
#define MAXN 510
#define lowbit(x)(((~(x))+1)&x)
#define inf 0x7fffffff
#define update(v) l[X[v]][Y[v]]=min(l[X[v]][Y[v]],l[X[v+1]][Y[v+1]]),r[X[v]][Y[v]]=max(r[X[v]][Y[v]],r[X[v+1]][Y[v+1]]);
bool f[MAXN][MAXN];
int n,m,h[MAXN][MAXN],ansv=0,ansm=0,l[MAXN][MAXN],r[MAXN][MAXN],X[MAXN*MAXN],Y[MAXN*MAXN],T[MAXN];
struct node{
int x,y;
node (int _x,int _y):x(_x),y(_y){
}
};
queueQ;
struct saver{
int l,r;
} Seg[MAXN];
int Sn=0;
bool Cmp(saver x,saver y){return x.l-inf){
Seg[Sn].l=l[1][i],Seg[Sn].r=r[1][i];
Sn++;
}
}
for(int i=0;i++