POJ 2375 Cow Ski Area 雪场缆车(强连通分量)

【问题描述】

  约翰的表哥罗恩生活在科罗拉多州。他进来打算教他的奶牛们滑雪,但是奶牛们非常害羞,不敢在游人如织的度假胜地滑雪。没办法,他只好自己建滑雪场了。

  罗恩的雪场可以划分为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;
}

你可能感兴趣的:(强连通分量)