HDU 4587 Two Nodes、POJ 2375 Reliable Nets (Tarjan)

TWO NODES

题意: 无向图删去两个点, 使得图存在的连通分量最多。

思路: 

我们知道删去割点,连通分量数目增加,其中一个点必然是割点,那么另一个点枚举就可以了

我们用cut[v]表示删去这个点 增加的连通分量数目 那么我们只要把求割点的bool数组改成int数组就可以了

这里我们要考虑一下对于根节点,如果是一个孤立节点是一个cc,删去以后没有cc了,那么减少了1,由于cut[v]初始化为0,-1即可

如果不是孤立节点 也要减去本身自己这个cc的1 也要-1

 参考code:

//
//  Created by TaoSama on 2015-06-14
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int N = 1e4 + 10;

int n, m;
int head[N], pnt[N], nxt[N], cnt;

void add_edge(int u, int v) {
    pnt[cnt] = v;
    nxt[cnt] = head[u];
    head[u] = cnt++;
}

int dfn[5005], low[5005], cut[5005], tim;
bool in[5005];
void dfs(int u, int f, int del) {
    dfn[u] = low[u] = ++tim;
    int son = 0;
    for(int i = head[u]; ~i; i = nxt[i]) {
        int &v = pnt[i];
        if(v == f || v == del) continue;
        if(!dfn[v]) {
            ++son;
            dfs(v, u, del);
            low[u] = min(low[u], low[v]);
            if(low[v] >= dfn[u]) cut[u]++;
        } else low[u] = min(low[u], dfn[v]);
    }
    if(f < 0) cut[u]--;
    //根节点要-1 孤立节点算1个cc没有儿子0-1 = -1 不是孤立节点的话减少1 总之都要-1
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    while(scanf("%d%d", &n, &m) == 2) {
        cnt = 0;
        memset(head, -1, sizeof head);
        for(int i = 0; i < m; ++i) {
            int u, v; scanf("%d%d", &u, &v);
            add_edge(u, v);
            add_edge(v, u);
        }

        int ans = -INF, cc;
        for(int i = 0; i < n; ++i) {
            cc = tim = 0;
            memset(dfn, 0, sizeof dfn);
            memset(low, 0, sizeof low);
            memset(cut, 0, sizeof cut);
            for(int j = 0; j < n; ++j) {
                if(i == j) continue;
                if(!dfn[j]) {
                    ++cc;
                    dfs(j, -1, i);
                }
            }
            for(int j = 0; j < n; ++j) {
                if(i == j) continue;
                ans = max(ans, cc + cut[j]);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

Reliable Nets

题意:无向图,找到一个删去任意一条边 还连通的的权和最小的图

思路:由于边数很小,枚举边,判断图是否连通,连通后判断是否只有一个bcc

bcc的定义 任意两点 至少存在两条 边不重复 的路径 


1-2-4-5   1-3-4-5 存在相交的路径 说明不在同一个bcc中 那么删掉4-5图就不连通了

参考code:

//
//  Created by TaoSama on 2015-06-14
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <vector>

using namespace std;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int N = 1e5 + 10;

int n, m;
int head[50], pnt[50], nxt[50], cost[50], cnt;

struct E {
    int u, v, c;
} G[50];

void add_edge(int u, int v, int c) {
    pnt[cnt] = v;
    cost[cnt] = c;
    nxt[cnt] = head[u];
    head[u] = cnt++;
}

int par[20], het[20];
int find(int x) {
    return par[x] = (par[x] == x ? x : find(par[x]));
}

bool isConnected(int s) {
    for(int i = 1; i <= n; ++i) par[i] = i, het[i] = 1;

    for(int i = 0; i < m; ++i) {
        if(s >> i & 1) {
            int u = find(G[i].u), v = find(G[i].v);
            if(u == v) continue;
            par[v] = u;
            het[u] += het[v];
        }
    }
    return het[find(1)] == n;
}

int build(int s) {
    int sum = 0;
    cnt = 0;
    memset(head, -1, sizeof head);
    for(int i = 0; i < m; ++i) {
        if(s >> i & 1) {
            add_edge(G[i].u, G[i].v, G[i].c);
            add_edge(G[i].v, G[i].u, G[i].c);
            sum += G[i].c;
        }
    }
    return sum;
}

int dfn[20], low[20], tim, bcc;
bool in[20];
stack<int> s;

bool dfs(int u, int f) {
    dfn[u] = low[u] = ++tim;
    in[u] = true; s.push(u);
    for(int i = head[u]; ~i; i = nxt[i]) {
        int &v = pnt[i];
        if(v == f) continue;
        if(!dfn[v]) {
            dfs(v, u);
            low[u] = min(low[u], low[v]);
        } else if(in[v]) low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]) {
        ++bcc;
        while(true) {
            int v = s.top(); s.pop();
            in[v] = false;
            if(v == u) break;
        }
    }
}

bool tarjan() {
    for(int i = 1; i <= n; ++i) dfn[i] = low[i] = in[i] = 0;
    tim = bcc = 0;
    for(int i = 1; i <= n; ++i) {
        if(!dfn[i]) dfs(i, -1);
    }
    return bcc == 1;
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    int kase = 0;
    while(scanf("%d%d", &n, &m) == 2 && (n || m)) {
        for(int i = 0; i < m; ++i) scanf("%d%d%d", &G[i].u, &G[i].v, &G[i].c);

        int ans = INF;
        for(int i = 0; i < 1 << m; ++i) {
            if(isConnected(i)) {
                int cur = build(i);
                if(cur > ans) continue;
                if(tarjan()) ans = cur;
            }
        }

        if(ans == INF)
            printf("There is no reliable net possible for test case %d.\n", ++kase);
        else printf("The minimal cost for test case %d is %d.\n", ++kase, ans);
    }
    return 0;
}


你可能感兴趣的:(Tarjan,BCC,割点)