题目描述
约翰的表哥罗恩生活在科罗拉多州.他近来打算教他的奶牛们滑雪,但是奶牛们非常害羞, 不敢在游人如织的度假胜地滑雪.没办法,他只好自己建滑雪场了. 罗恩的雪场可以划分为$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);
}