hdu4738
题意
n个岛m座桥的无向图,每座桥上有若干个士兵,派出最少的士兵只炸毁一座桥,使得n个岛不连通(派出的士兵不能少于驻守的士兵,特别的改桥的驻守人数为0的时候要派一个士兵)。
思路
用tarjan算法,满足dfn[u] < low[v]的(u,v)就是割边,直接处理出来取最小值,这里还有一个问题就是有重边,所以要判断一下。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 +7;
const int maxm = 1000000 + 7;
typedef long long ll;
int n, m, low[maxn], dfn[maxn], vis[maxn], tot;//scc连通分量数
int head[maxn], to[maxm], nex[maxm], edge[maxm], cnt;
stack<int> st;//辅助栈
int e[maxn][maxn];
void add(int x, int y, int z) {
to[cnt] = y;
edge[cnt] = z;
nex[cnt] = head[x];
head[x] = cnt++;
}
vector<int> g;
void tarjan(int u, int fx)
{
dfn[u] = low[u] = ++tot;
st.push(u);
vis[u] = 1;
for (int i = head[u]; ~i; i = nex[i]) {
int v = to[i];
if(!dfn[v]) {//如果没访问过
tarjan(v, u);
low[u] = min(low[u], low[v]);//能连通到的最小根
if(dfn[u] < low[v] && e[u][v] == 1) {//把重边问题排除
g.push_back(edge[i]);
}
}
else if(v != fx)//不走反路
low[u] = min(low[u], dfn[v]);
}
}
int main()
{
while (scanf("%d%d", &n, &m) && n)
{
g.clear();
memset(low, 0, sizeof(low));
memset(dfn, 0, sizeof(dfn));
memset(vis, 0, sizeof(vis));
memset(head, -1, sizeof(head));
memset(e, 0, sizeof(e));
tot = cnt = 0;
while (!st.empty()) st.pop();
for (int i = 1; i <= m; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
e[a][b]++;
e[b][a]++;
}
tarjan(1, 1);
bool f = 1;
for (int i = 1; i <= n; i++) {
if(dfn[i] == 0) {
f = 0;
break;
}
}
if(!f) {
printf("0\n");
continue;
}
int ans = 0x3f3f3f3f;
for (int i = 0; i < g.size(); i++)
ans = min(ans, g[i]);
if(ans == 0x3f3f3f3f) {
printf("-1\n");
continue;
}
if(ans == 0) ans = 1;
printf("%d\n", ans);
}
}