#include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iomanip> #include<algorithm> #include<queue> #include<ctime> #define ll long long #define rg register #define N 550 using namespace std; int n,m; int dx[4]={1,0,-1,0}; int dy[4]={0,1,0,-1}; ll map[N][N];//记录每个城市的高度 bool b[N][N],ans[N][N];//b[][]记录这个城市是否流过了(我也不知道有不有用) //ans[i][j]表示临河的第i个城市通过......可以让沙漠第j个城市有水(有水为true,没水为false) ll s[N],ss[N];//s[]用于储存沙漠中第i个城市可以由几个城市引水 //ss[]用于暂时存一下s[]中的情况,见代码吧 struct water{ int x,y; }ljl[1000050];//bfs的队列,水流到第[x][y]城市了 inline int read() { int s=0,m=1;char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')m=-1,ch=getchar(); while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar(); return s*m; } void Bfs() { for(int k=1;k<=n;++k) { if(map[1][k]<map[1][k-1]||map[1][k]<map[1][k+1])//这个很重要!!! continue; //剪枝,如果两边都比它高,它也就没用了 memset(b,0,sizeof(b)); int head=0,tail=1;//套一波广搜模板 ljl[1].x=1,ljl[1].y=k; if(ljl[1].x==m)ans[k][k]=1;//河和沙漠挨在一坨 while(head<tail) { ++head; for(int i=0;i<4;++i) { int nx=ljl[head].x+dx[i],ny=ljl[head].y+dy[i]; if(nx>=1&&nx<=m&&ny>=1&&ny<=n&&!b[nx][ny])//边界 { if(map[nx][ny]<map[ljl[head].x][ljl[head].y])//条件 { ++tail,b[nx][ny]=1; ljl[tail].x=nx,ljl[tail].y=ny; if(nx==m) { ans[k][ny]=1; } } } } } } } bool check() //用来检查这种开贮水池方法是否行得通 { for(int i=1;i<=n;++i) { if(!s[i])return 0; } return 1; } void copy(int hh) { if(hh)//保存一下合法但不一定最优的答案 for(int i=1;i<=n;++i) { ss[i]=s[i]; } else//减去城市后发现不合法了肯定会到刚刚的方案再去寻找 for(int i=1;i<=n;++i) { s[i]=ss[i]; } } void jian(int kk) //减去一个贮水池 { for(int i=1;i<=n;++i) { s[i]-=ans[kk][i]; } } int main() { m=read();n=read(); for(int i=1;i<=m;++i) for(int j=1;j<=n;++j) map[i][j]=read(); Bfs(); for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) { //先假设我在河边上每个城市都要开贮水池 s[j]+=ans[i][j]; } } if(!check())//去检查是否所有沙漠城市都有水了 { int z=0; puts("0"); for(int i=1;i<=n;++i) { if(s[i]==0)++z;//没水就计入答案 } printf("%d\n",z); return 0; } puts("1"); int answer=n;//假设贮水池全都要 for(int i=1;i<=n;++i) { if(map[1][i]<map[1][i-1]||map[1][i]<map[i][i+1])//同bfs里的剪枝原理一样 { answer--;continue; } copy(1);//储存一下此时的答案 jian(i);//试一试减去这个城市的贮水池 if(!check())//判断是否还合法 copy(0);//不合法就不能减,回到不减之前 else answer--;//合法就减去这个(半个贪心吧!) } printf("%d\n",answer); return 0; }