/*
*State: POJ3177    Accepted    340K    16MS    C++    1877B
*题目大意:
*        给出一个无向连通图,判断最少需要加多少条边,才能使得
*        任意两点之间至少有两条相互"边独立"的道路.注意,可能
*        含有重边.
*解题思路:
*        先缩点,之后形成一棵树,然后求(叶子节点数量+1)/ 2即可。
*/
View Code
#include <iostream>
#include <vector>
#include <stack>
using namespace std;

const int MAXN = 5005;
const int MAXE = 10005;

vector<int> vec[MAXN];
stack<int> S;
int dfn[MAXN], low[MAXN], step;
int id[MAXN], scc;

void init()
{
    while(!S.empty())
        S.pop();

    step = 0;
    scc = 1;
    for(int i = 0; i < MAXN; i++)
    {
        id[i] = -1;
        vec[i].clear();
        dfn[i] = low[i] = -1;
    }
}

void addEdge(int u, int v)
{
    vec[u].push_back(v);
    vec[v].push_back(u);
}

void tarjan_scc(int n, int father)
{
    dfn[n] = low[n] = ++step;
    S.push(n);
    int flag = 0;
    for(unsigned i = 0; i < vec[n].size(); i++)
    {
        int son = vec[n][i];
        if(son == father && !flag)
        {
            flag = 1;
            continue;
        }

        if(dfn[son] == -1)
        {
            tarjan_scc(son, n);
            low[n] = min(low[n], low[son]);
        }
        else
            low[n] = min(low[n], dfn[son]);
    }

    if(low[n] == dfn[n])
    {
        int tmp;
        do
        {
            tmp = S.top();
            id[tmp] = scc;
        //    cout << tmp << " ";
            S.pop();
        }while(!S.empty() && tmp != n);
        scc++;
        //cout << endl << "---------------" << endl;
    }
}

void deal_scc(int n, int &sol)
{
    int u, v;
    int du[MAXN] = {0};
    for(int i = 1; i <= n; i++)
    {
        for(unsigned j = 0; j < vec[i].size(); j++)
        {
            u = i, v = vec[i][j];
            if(id[u] == id[v])
                continue;
            else
            {
                du[id[v]]++; du[id[u]]++;
            }
        }
    }
    int sum = 0;
    for(int i = 1; i < scc; i++)
    {
        if(du[i] == 2)
            sum++;
    }
    sum++;
    sol = sum / 2;
}

int main(void)
{
#ifndef ONLINE_JUDGE
    //freopen("in.txt", "r", stdin);
#endif

    int n, m;
    while(scanf("%d %d", &n, &m) == 2)
    {
        init();
        int u, v;
        for(int i = 0; i < m; i++)
        {
            scanf("%d %d", &u, &v);
            addEdge(u, v);
        }
        tarjan_scc(1, 1);
        int sol;
        deal_scc(n, sol);
        printf("%d\n", sol);
        //cout << "****************" << endl;
    }
    return 0;
}
//POJ3352
//State: POJ3352    Accepted    280K    47MS    C++    1865B
//题意与上述的题一模一样
View Code
#include <iostream>
#include <vector>
#include <stack>
using namespace std;

const int MAXN = 1005;

vector<int> vec[MAXN];
stack<int> S;
int dfn[MAXN], low[MAXN], step;
int id[MAXN], scc;

void init()
{
    while(!S.empty())
        S.pop();

    step = 0;
    scc = 1;
    for(int i = 0; i < MAXN; i++)
    {
        id[i] = -1;
        vec[i].clear();
        dfn[i] = low[i] = -1;
    }
}

void addEdge(int u, int v)
{
    vec[u].push_back(v);
    vec[v].push_back(u);
}

void tarjan_scc(int n, int father)
{
    dfn[n] = low[n] = ++step;
    S.push(n);
    int flag = 0;
    for(unsigned i = 0; i < vec[n].size(); i++)
    {
        int son = vec[n][i];
        if(son == father && !flag)
        {
            flag = 1;
            continue;
        }

        if(dfn[son] == -1)
        {
            tarjan_scc(son, n);
            low[n] = min(low[n], low[son]);
        }
        else
            low[n] = min(low[n], dfn[son]);
    }

    if(low[n] == dfn[n])
    {
        int tmp;
        do
        {
            tmp = S.top();
            id[tmp] = scc;
        //    cout << tmp << " ";
            S.pop();
        }while(!S.empty() && tmp != n);
        scc++;
        //cout << endl << "---------------" << endl;
    }
}

void deal_scc(int n, int &sol)
{
    int u, v;
    int du[MAXN] = {0};
    for(int i = 1; i <= n; i++)
    {
        for(unsigned j = 0; j < vec[i].size(); j++)
        {
            u = i, v = vec[i][j];
            if(id[u] == id[v])
                continue;
            else
            {
                du[id[v]]++; du[id[u]]++;
            }
        }
    }
    int sum = 0;
    for(int i = 1; i < scc; i++)
    {
        if(du[i] == 2)
            sum++;
    }
    sum++;
    sol = sum / 2;
}

int main(void)
{
#ifndef ONLINE_JUDGE
    freopen("in3352.txt", "r", stdin);
#endif

    int n, m;
    while(scanf("%d %d", &n, &m) == 2)
    {
        init();
        int u, v;
        for(int i = 0; i < m; i++)
        {
            scanf("%d %d", &u, &v);
            addEdge(u, v);
        }
        tarjan_scc(1, 1);
        int sol;
        deal_scc(n, sol);
        printf("%d\n", sol);
        //cout << "****************" << endl;
    }
    return 0;
}
posted on 2012-08-18 09:28  cchun  阅读(254)  评论(0编辑  收藏  举报