题目描述
约翰的表哥罗恩生活在科罗拉多州.他近来打算教他的奶牛们滑雪,但是奶牛们非常害羞, 不敢在游人如织的度假胜地滑雪.没办法,他只好自己建滑雪场了. 罗恩的雪场可以划分为$W列L行(1≤W≤500;1≤L≤500),每个方格有一个特定的高度H(O≤日≤9999).$奶牛可以在相临方格间滑雪,而且不能由低到高滑. 为了保证任意方格可以互通,罗恩打算造一些直达缆车.缆车很强大,可以连接任意两个方格,而且是双向的.而且同一个方格也可以造多台缆车. 但是缆车的建造费用贵得吓人,所以他希望造尽量少的缆车.那最少需要造多少台呢?
思路
首先看到这题感觉挺简单的,暴力$flood fill$,然后直接根据颜色数贪心即可。后来我发现我还是太naive了。
正解:要使整张图形成一个强联通分量,那么必须满足加边之后没有出度为0的点和入度为0的点,于是我们只需要把每个相同高度的地方先染色,然后暴力从高往低连边,统计入度和出度的个数。最后统计入度为0的颜色数和出度为0的颜色数,比一个max即可。
下面放上简单易懂的代码。
code
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<queue> #include<map> using namespace std; const int N=510; int a[N][N]; int n,m; int col[N][N],color; map<int,int>vis[N*N]; int dx[5]={0,0,1,-1}; int dy[5]={1,-1,0,0}; int in[N*N],out[N*N]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline bool chk(int x,int y) { return (x>=1&&x<=n&&y>=1&&y<=m); } inline void bfs1(int x,int y) { color++; queue<int>q1,q2; col[x][y]=color; q1.push(x);q2.push(y); while(!q1.empty()) { int xx=q1.front(),yy=q2.front(); for(int i=0;i<4;i++) { x=xx+dx[i];y=yy+dy[i]; if(!col[x][y]&&chk(x,y)&&a[xx][yy]==a[x][y]) { q1.push(x);q2.push(y); col[x][y]=color; } } q1.pop();q2.pop(); } } int main() { m=read();n=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!col[i][j])bfs1(i,j); /*cout<<endl; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) cout<<col[i][j]<<" ";cout<<endl; }*/ if(color==1){cout<<"0";return 0;} for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { for(int k=0;k<4;k++) { int x=i+dx[k],y=j+dy[k]; if(!chk(x,y))continue; if(!vis[col[i][j]][col[x][y]]&&a[i][j]>a[x][y]) { out[col[i][j]]++; in[col[x][y]]++; vis[col[i][j]][col[x][y]]=1; vis[col[x][y]][col[i][j]]=1; } } } int ans1=0,ans2=0; for(int i=1;i<=color;i++) { if(!in[i])ans1++; if(!out[i])ans2++; } cout<<max(ans1,ans2); }