/*
http://acm.hdu.edu.cn/showproblem.php?pid=4738
题意:有n个岛,曹操在一些岛之间建了一些桥,每个桥上有一些士兵把守,周瑜只有一个炸弹只能炸掉一个桥,炸弹需要士兵 带过去,士兵的数量不能小于目标桥的守卫,求出最少要派出多少士兵。
思路:
裸割边
坑:
1:原图不连通,ans=0.
2: m<=n^2 显然有重边,重边必然不是桥,处理重边 直接标记.
3: 最小桥边权为0的时候,ans=1,至少要派一个人运炸弹。。。
*/
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
const int maxn = 1005;
const int inf = 1<<30;
int n,m;
int time,ans;
int low[maxn],dfn[maxn];
int wmap[maxn][maxn];
int p[maxn];
vector<int>map[maxn];
void tarjan( int u, int fa )
{
low[u] = dfn[u] = ++time;
for( int i = 0; i < map[u].size(); i ++ )
{
int v = map[u][i];
if( v == fa ) //判定回边
continue;
if( !dfn[v] )
{
tarjan( v,u );
low[u] = low[u] <= low[v] ? low[u]:low[v];
if( low[v] > dfn[u] && wmap[u][v] != -2 )
{
ans = ans < wmap[u][v] ?ans : wmap[u][v] ;
}
}
else
low[u] = low[u] <= dfn[v] ? low[u]:dfn[v];
}
}
int find( int x )
{
if( p[x] == x )
return x;
else
return p[x] = find(p[x]);
}
void merge( int a,int b )
{
int x = find(a);
int y = find(b);
p[y] = x;
}
void init() //初始化
{
time = 0,ans = inf;
for( int i = 1; i <= n; i ++ )
{
map[i].clear();
p[i] = i;
}
memset( low,0,sizeof(low) );
memset( dfn,0,sizeof(dfn) );
memset( wmap,-1,sizeof(wmap) );
}
int main()
{
int u,v,d;
while( scanf("%d%d",&n,&m) != EOF , (n||m) )
{
init();
for( int i = 1; i <= m; i ++ )
{
scanf("%d%d%d",&u,&v,&d);
merge( u,v ); //合并并查集
map[u].push_back( v );
map[v].push_back( u );
if( wmap[u][v] == -1 ) //标记重边
{
wmap[u][v] = d;
wmap[v][u] = d;
}
else
{
wmap[u][v] = -2;
wmap[v][u] = -2;
}
}
int count = 0;
for( int i = 1; i <= n; i ++ ) // 并查集判断是否联通
{
if( p[i] == i )
count++;
}
if( count > 1 ) { puts("0"); continue; }
else
tarjan(1,-1);
if( ans == 0 ) puts("1");
else if( ans == inf ) puts("-1");
else printf("%d\n",ans);
}
return 0;
}
hdu - 4738 Caocao's Bridges 割边
最新推荐文章于 2020-10-19 15:37:16 发布