poj2375强连通图最少添加边数

Farmer John's cousin, Farmer Ron, who lives in the mountains of Colorado, has recently taught his cows to ski. Unfortunately, his cows are somewhat timid and are afraid to ski among crowds of people at the local resorts, so FR has decided to construct his own private ski area behind his farm. 

FR's ski area is a rectangle of width W and length L of 'land squares' (1 <= W <= 500; 1 <= L <= 500). Each land square is an integral height H above sea level (0 <= H <= 9,999). Cows can ski horizontally and vertically between any two adjacent land squares, but never diagonally. Cows can ski from a higher square to a lower square but not the other way and they can ski either direction between two adjacent squares of the same height. 

FR wants to build his ski area so that his cows can travel between any two squares by a combination of skiing (as described above) and ski lifts. A ski lift can be built between any two squares of the ski area, regardless of height. Ski lifts are bidirectional. Ski lifts can cross over each other since they can be built at varying heights above the ground, and multiple ski lifts can begin or end at the same square. Since ski lifts are expensive to build, FR wants to minimize the number of ski lifts he has to build to allow his cows to travel between all squares of his ski area. 

Find the minimum number of ski lifts required to ensure the cows can travel from any square to any other square via a combination of skiing and lifts.

Input

* Line 1: Two space-separated integers: W and L 

* Lines 2..L+1: L lines, each with W space-separated integers corresponding to the height of each square of land.

Output

* Line 1: A single integer equal to the minimal number of ski lifts FR needs to build to ensure that his cows can travel from any square to any other square via a combination of skiing and ski lifts

Sample Input

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

Sample Output

3

Hint

This problem has huge input data,use scanf() instead of cin to read data to avoid time limit exceed. 

OUTPUT DETAILS: 

FR builds the three lifts. Using (1, 1) as the lower-left corner, 
the lifts are (3, 1) <-> (8, 2), (7, 3) <-> (5, 2), and (1, 3) <-> 
(2, 2). All locations are now connected. For example, a cow wishing 
to travel from (9, 1) to (2, 2) would ski (9, 1) -> (8, 1) -> (7, 
1) -> (7, 2) -> (7, 3), take the lift from (7, 3) -> (5, 2), ski 
(5, 2) -> (4, 2) -> (3, 2) -> (3, 3) -> (2, 3) -> (1, 3), and then 
take the lift from (1, 3) - > (2, 2). There is no solution using 
fewer than three lifts.


 

题意:n*m的一个矩阵 如果在一个点上 可以往上下左右4个点 并且必须大于等于要去的点 可以安装一个任意门 每个任意门可以连接容易2个点

求最少安装多少个任意门 可以是全通连通

思路:强连通分量缩点 求出度为0和入读为0的连通分量2者的最大值 特判全图强连通的情况

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#include<stack>
using namespace std;
int dx[]= {0,0,1,-1};
int dy[]= {1,-1,0,0};
/* Tarjan算法
* 复杂度O(N+M) */
const int MAXN = 250009;//点数
const int MAXM = 4*250009;//边数
struct Edge
{
    int to,next;
} edge[MAXM];
stack <int> s;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc,belong[1]=2表示1点在第2个强联通分量里。
int Index,top;
int scc;//强连通分量的个数
int Instack[MAXN];
int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc
//num数组不一定需要,结合实际情况
void addedge(int u,int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void Tarjan(int u)
{
    int v;
    Low[u] = DFN[u] = ++Index;  //刚搜到一个节点时Low = DFN;
    Stack[top++] = u;  //将该节点入栈
    Instack[u] = 1;  //将入栈标记设置为1
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if(!DFN[v])
        {
            Tarjan( v);
            if( Low[u] > Low[v] )Low[u] = Low[v];
        }
        else if(Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if(Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc ]++;
        }
        while( v != u);
    }
}


void solve(int N)
{
    memset( DFN,0,sizeof(DFN));
    memset( Instack,false, sizeof(Instack) );
    memset( num,0,sizeof(num));
    Index = scc = top = 0;
    for(int i = 1; i <= N; i++)
        if(!DFN [i])
            Tarjan(i);
}
void init()
{
    tot = 0;
    memset( head, -1,sizeof (head));
}
int out[MAXN]= {};
int in[MAXN]= {};
//map <int,int> mp[MAXN];
int a[600][600];
int main()
{
    int l,w;
    //cin>>l>>w;
    scanf("%d%d",&l,&w);
    init();
    for(int i=1; i<=w; i++)
    {
        for(int j=1; j<=l; j++)
        {
            // cin>>a[i][j];
            scanf("%d",&a[i][j]);
        }
    }
    for(int i=1; i<=w; i++)
    {
        for(int j=1; j<=l; j++)
        {
            for(int k=0; k<4; k++)
            {
                int x=i;
                int y=j;
                int nx=x+dx[k];
                int ny=y+dy[k];
                if(nx>=1&&ny>=1&&nx<=w&&ny<=l&&a[x][y]>=a[nx][ny])
                {
                        int s1=(x-1)*l+y;
                        int s2=(nx-1)*l+ny;
                        //mp[s1][s2] = 1;
                        addedge(s1,s2);

                }
            }
        }
    }
    int n=w*l;
    solve(n);
    for(int i= 1;i <=n; i++)
	{
		for(int ee = head[i]; ee != -1; ee = edge[ee].next)
		{
			int v = edge[ee].to;
			 if ( Belong[i] != Belong[v])
                {
                    out[Belong[i]]++;
                    in[Belong[v]]++;
                }
		}
	}
    int  ans1 = 0,ans2 = 0;
    for (int i = 1; i <= scc; i++)
    {
        if (in[i] == 0) ans1++;
        if (out[i] == 0) ans2++;
    }
    int ans=max(ans1,ans2);
    if(scc==1)
        ans=0;
    printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_40859951/article/details/87902455