题意:本题描述了一片滑雪场,并且规定奶牛从一个点只能向它相邻的并且高度不大于它的点运动,现在想要在某些点对之间加上缆车使得奶牛也可以从较低点到达较高点,问最少需要多少辆这样的缆车就可以使得奶牛可以从任意一个点运动到滑雪场的每个角落。
思路:即问至少加多少条边使图变成强联通图,先缩点成DAG。
不难知道强连通分量的所有节点的入度和出度均不为0,可以统计DAG上的入度和出度为0的个数分别是a,b。然后答案即为max(a,b)。
只是发现入度为0和出度为0的点可以按某种方式相连接总能构造出一个强连通分量,然后多余的abs(a-b)个节点也总能可某些点构成强连通分量,但是没有准确的证明orz
//9908K 266MS
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int mapp[555][555];
int c,r;
int gro[555][555];
bool indeg[250100];
bool outdeg[250100];
int col;
int nxt[4][2]={0,1,0,-1,-1,0,1,0};
void getgro(int x,int y)
{
gro[x][y]=col;
for(int i=-1;i<=1;i++)
for(int j=-1;j<=1;j++)
{
if(j==0&&i==0) continue;
if(j&&i) continue;
if(gro[x+i][y+j]) continue;
if(mapp[x+i][y+j]==mapp[x][y]) getgro(x+i,y+j);
}
}
void ini()
{
memset(mapp,-1,sizeof(mapp));
memset(gro,0,sizeof(gro));
col=0;
memset(indeg,0,sizeof(indeg));
memset(outdeg,0,sizeof(outdeg));
}
int main()
{
while(~scanf("%d%d",&c,&r))
{
ini();
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++) scanf("%d",&mapp[i][j]);
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
if(gro[i][j]==0) col++,getgro(i,j);
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
for(int k=0;k<4;k++)
{
int nx=i+nxt[k][0],ny=j+nxt[k][1];
if(nx<1||nx>r||ny<1||ny>c) continue;
if(gro[i][j]==gro[nx][ny]) continue;
if(mapp[i][j]>mapp[nx][ny]) indeg[gro[nx][ny]]=1,outdeg[gro[i][j]]=1;
else indeg[gro[i][j]] = 1,outdeg[gro[nx][ny]] = 1;
}
int cnta=0,cntb=0;
for(int i=1;i<=col;i++)
{
if(indeg[i]==0) cnta++;
if(outdeg[i]==0) cntb++;
}
if(col!=1) printf("%d\n",max(cnta,cntb));
else puts("0");
}
return 0;
}