luogu 1066 引水入城(bfs+贪心)
90分,有一个点TLE....
首先可以证明一个东西,如果从上面一排的某个点bfs一次到最下面一排的饮水点不是一个区间的话,那么最后一定所有饮水点不会被覆盖完的。
证明考虑反证法。
所以从上面一排的每个点bfs一次得到一个区间。题目转化为给出m个区间覆盖m个点的最小区间选择数。
显然是个明显的贪心,以左区间端点为第一关键字升序排序,右区间端点为第二关键字降序排序,那么每次贪心的选择一个覆盖最大的区间即可。
时间复杂度O(n*m^2+mlogm).需要常数优化。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-7 # define MOD 1024523 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int x=0;char ch=getchar(); while(ch<'0'||ch>'9'){ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=505; //Code begin... int G[N][N], ps[4][2]={1,0,-1,0,0,1,0,-1}; bool vis[N][N], mark[N], flag=true; struct Node{int l, r;}node[N]; queue<PII>que; bool comp(Node a, Node b){ if (a.l!=b.l) return a.l<b.l; return a.r>b.r; } int main () { int n, m, dx, dy; PII tmp; n=Scan(); m=Scan(); FOR(i,1,n) FOR(j,1,m) G[i][j]=Scan(); FOR(i,1,m) { mem(vis,false); que.push(mp(1,i)); vis[1][i]=true; while (!que.empty()) { tmp=que.front(); que.pop(); FO(j,0,4) { dx=tmp.first+ps[j][0], dy=tmp.second+ps[j][1]; if (dx<1||dy<1||dx>n||dy>m||vis[dx][dy]||G[tmp.first][tmp.second]<=G[dx][dy]) continue; vis[dx][dy]=true; que.push(mp(dx,dy)); } } FOR(j,1,m) { if (vis[n][j]) { mark[j]=true; if (flag) { if (!vis[n][j-1]) { if (node[i].l) flag=false; else node[i].l=j; } if (!vis[n][j+1]) node[i].r=j; } } } } int ans=0; FOR(i,1,m) if (!mark[i]) ++ans; if (ans) printf("0\n%d\n",ans); else { sort(node+1,node+m+1,comp); int now=1; while (node[now].r==0) ++now; int ma=node[now].r, r; ++now; ++ans; while (now<=m) { r=ma; if (r==m) break; while (now<=m&&node[now].l<=r+1) ma=max(ma,node[now].r), ++now; ++ans; } printf("1\n%d\n",ans); } return 0; }