【问题描述】
约翰的表哥罗恩生活在科罗拉多州。他进来打算教他的奶牛们滑雪,但是奶牛们非常害羞,不敢在游人如织的度假胜地滑雪。没办法,他只好自己建滑雪场了。
罗恩的雪场可以划分为W列L行,每个方格都有一个特定的高度H。奶牛可以在相邻邻方格间滑雪,而且不能由低到高滑。
为了保证任意方格可以互通,罗恩打算造一些直达缆车。缆车很强大,可以连接任意两个方格,而且是双向的。而且同一个方格可以造多台缆车。但是缆车的建造费用贵的吓人,所以他希望造尽量少的缆车。那最少需要多少台呢?
【输入格式】
第一行:W和L
接下来输出W*H的矩阵地图。
【输出格式】
最小的缆车数
【输入样例】
9 3
1 1 1 2 2 2 1 1 1
1 2 1 2 3 2 1 2 1
1 1 1 2 2 2 1 1 1
【输出样例】
3
【样例解释】
把左下角作为(1,1),建立(3,1) <->(8,2),(7,3)<->(5,2),(1,3)<->(2,2)三部缆车,这样任意两个格子可以互通。
【数据范围】
1<=W<=500;1<=L<=500
0<=H<=9999
高度相等的格子可以互相来往,构成了强连通,所以可以先找出图中的强连通分量,然后缩点。因为可以从高处往低处滑,在缩点时也要连接一条有向边,这样就得到了一个DAG图。题目要求任意方格可以互通,所以最后的问题就是缩点得到的DAG图最少加几条边使得强连通。之后统计缩点后得到的点入度为0,出度为0的个数,答案即为最大值。注意当图中只有1个连通分量时,需特判。
#include
#include
#include
#include
using namespace std;
const int maxn=503;
int w,l,mat[maxn][maxn],rd[maxn*maxn],cd[maxn*maxn],belong[maxn][maxn];
int dx[]={0,0,-1,1};
int dy[]={1,-1,0,0};
struct data
{
int x,y;
};
void dfs(int x,int y,int scc) //找强连通分量
{
belong[x][y]=scc;
for(int k=0;k<4;k++)
{
int tx=x+dx[k];
int ty=y+dy[k];
if(tx<1||ty<1||tx>l||ty>w) continue;
if(belong[tx][ty]) continue;
if(mat[tx][ty]!=mat[x][y]) continue;
dfs(tx,ty,scc);
}
}
int main()
{
//freopen("1.txt","r",stdin);
scanf("%d %d",&w,&l);
for(int i=1;i<=l;i++)
for(int j=1;j<=w;j++)
{
scanf("%d",&mat[i][j]);
}
memset(belong,0,sizeof(belong));
int scc=0;
for(int i=1;i<=l;i++)
for(int j=1;j<=w;j++)
{
if(!belong[i][j]) dfs(i,j,++scc);
}
memset(rd,0,sizeof(rd));
memset(cd,0,sizeof(cd));
for(int i=1;i<=l;i++) //缩点
for(int j=1;j<=w;j++)
{
for(int k=0;k<4;k++)
{
int tx=i+dx[k];
int ty=j+dy[k];
if(tx<1||ty<1||tx>l||ty>w) continue;
if(belong[tx][ty]==belong[i][j]) continue;
if(mat[i][j]<=mat[tx][ty]) continue;
cd[belong[i][j]]++,rd[belong[tx][ty]]++;
}
}
int a=0,b=0;
for(int i=1;i<=scc;i++)
{
if(rd[i]==0) a++;
if(cd[i]==0) b++;
}
if(scc==1) printf("0"); //图中只有1个连通分量,需特判
else printf("%d",max(a,b));
return 0;
}