poj 2375 Cow Ski Area 【SCC缩点 求最少增加几条边使图强连通】

Cow Ski Area
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 2868   Accepted: 823

Description

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.


有一段时间没写SCC了,纯手打一发,没想到1A了。


题意:有一个L*W的田地,每个位置都有一定的高度。若a处高度 >= b处高度,则a可以到达b(不代表b可达a)。现在问你最少增加几条边使图中任意两个位置都可以互相可达。


思路:求出SCC,缩点后。求出出度为0的SCC数目ans1,入度为0的SCC数目ans2。答案就是max(ans1, ans2)。


AC代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define MAXN 250000+10
#define MAXM 1000000+10
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int from, to, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int low[MAXN], dfn[MAXN];
int dfs_clock;
int sccno[MAXN], scc_cnt;
stack<int> S;
bool Instack[MAXN];
int W, L;
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
int point(int x, int y)
{
    return (x-1) * W + y;
}
void addEdge(int u, int v)
{
    Edge E = {u, v, head[u]};
    edge[edgenum] = E;
    head[u]= edgenum++;
}
bool judge(int x, int y)
{
    return x >= 1 && x <= L && y >= 1 && y <= W;
}
int Map[510][510];
void getMap()
{
    int move[4][2] = {0,1, 0,-1, 1,0, -1,0};
    for(int i = 1; i <= L; i++)// W L不要反了
    {
        for(int j = 1; j <= W; j++)
            scanf("%d", &Map[i][j]);
    }
    for(int i = 1; i <= L; i++)
    {
        for(int j = 1; j <= W; j++)
        {
            for(int k = 0; k < 4; k++)
            {
                int x = i + move[k][0];
                int y = j + move[k][1];
                if(judge(x, y) && Map[x][y] <= Map[i][j])
                    addEdge(point(i, j), point(x, y));
            }
        }
    }
}
void tarjan(int u, int fa)
{
    int v;
    low[u] = dfn[u] = ++dfs_clock;
    S.push(u);
    Instack[u] = true;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(Instack[v])
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        scc_cnt++;
        for(;;)
        {
            v = S.top();S.pop();
            Instack[v] = false;
            sccno[v] = scc_cnt;
            if(u == v) break;
        }
    }
}
void find_cut(int l, int r)
{
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(sccno, 0, sizeof(sccno));
    memset(Instack, false, sizeof(Instack));
    dfs_clock = scc_cnt = 0;
    for(int i = l; i <= r; i++)
        if(!dfn[i]) tarjan(i, -1);
}
int out[MAXN], in[MAXN];
void suodian()
{
    for(int i = 1; i <= scc_cnt; i++) in[i] = out[i] = 0;
    for(int i = 0; i < edgenum; i++)
    {
        int u = sccno[edge[i].from];
        int v = sccno[edge[i].to];
        if(u != v)
            out[u]++, in[v]++;
    }
}
void solve()
{
    find_cut(1, W*L);
    if(scc_cnt == 1)//注意
    {
        printf("%d\n", 0);
        return ;
    }
    suodian();
    int ans1 = 0, ans2 = 0;
    for(int i = 1; i <= scc_cnt; i++)
    {
        if(in[i] == 0)
            ans1++;
        if(out[i] == 0)
            ans2++;
    }
    printf("%d\n", max(ans1, ans2));
}
int main()
{
    while(scanf("%d%d", &W, &L) != EOF)
    {
        init();
        getMap();
        solve();
    }
    return 0;
}



你可能感兴趣的:(poj 2375 Cow Ski Area 【SCC缩点 求最少增加几条边使图强连通】)