剛拿到這道題時挺有思路,無奈平日裡只敲過找割頂的代碼,判橋的代碼當時自己也沒仔細敲。 當時一把淚啊,忽然感覺自己的圖論才只是剛搞了個起步啊。。 題目有神坑。 就是先判是否連通,不連通直接輸出0; 還有一個比較坑的是有重邊的情況,那這樣就有重邊的兩點之間就不可能存在橋。 再就是橋上無士兵把守也要派一個人去炸。 。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 1500;
int dfs_clock, current_clock, ans, current_cc;
int adj[maxn][maxn], iscut[maxn], vis[maxn], pre[maxn], low[maxn];
vector<int> G[maxn];
int n, m, a, b, c, INF = 10000000;
void dfs(int u)
{
vis[u] = 1;
//PREVISIT(u); 訪問u之前的操作
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(!vis[v]) dfs(v);
}
//POSTVISIT(u); 訪問結點u之後的操作
}
void find_cc() //給連通分量標號
{
current_cc = 0;
memset(vis, 0, sizeof(vis));
for(int u = 1; u <= n; u++) if(!vis[u])
{
current_cc++;
dfs(u);
}
}
int dfs_bridge(int u,int fa) //u在dfs樹中的父結點是fa
{
int lowu = pre[u] = ++dfs_clock;
int child = 0; //子結點數目
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(!pre[v]) //沒有訪問過v
{
child++;
int lowv = dfs_bridge(v, u);
lowu = min(lowu, lowv);
if(lowv >= pre[u])
{
iscut[u] = true; //割點判斷
if(lowv > pre[u] && adj[u][v] != -2) //橋的判斷可以相應靈活處理
ans = min(ans, adj[u][v]);
}
}
else if(pre[v] < pre[u] && v != fa)
lowu = min(lowu, pre[v]); //用反向邊更新u的low函數
}
if(fa < 0 && child == 1)
{
// 但是不用加是否單獨判橋的判斷?
iscut[u] = 0; //應該是避免單結點判橋、割頂的情況吧
}
low[u] = lowu;
return lowu;
}
void init()
{
memset(pre, 0, sizeof(pre));
memset(iscut, 0, sizeof(iscut));
memset(adj, -1 ,sizeof(adj));
for(int i = 0; i <= n; i++)
G[i].clear();
}
int main()
{
while(scanf("%d%d",&n, &m) != EOF)
{
if(!n && !m) break;
init();
while(m--)
{
scanf("%d%d%d", &a, &b, &c);
if(adj[a][b] == -1)
{
G[a].push_back(b);
G[b].push_back(a);
adj[a][b] = c;
adj[b][a] = c;
}
else // 兩點之間有兩條邊肯定不可能是橋
{
adj[a][b] = -2;
adj[b][a] = -2;
}
}
ans = INF;
dfs(1); find_cc();
//printf("~%d\n",current_cc);
if(current_cc >= 2) { printf("0\n"); continue;}
else dfs_bridge(1, -1);
if(ans == 0) printf("1\n");
else if(ans == INF ) printf("-1\n");
else printf("%d\n", ans);
}
return 0;
}