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;
}