http://acm.hdu.edu.cn/showproblem.php?pid=4738
这是个有点坑的题目。
题目:
曹操在长江上建立了一些点,点之间有一些边连着。如果这些点构成的无向图变成了连通图,那么曹操就无敌了。刘备为了防止曹操变得无敌,就打算去摧毁连接曹操的点的桥。但是诸葛亮把所有炸弹都带走了,只留下一枚给刘备。所以刘备只能炸一条桥。
题目给出n,m。表示有n个点,m条桥。
接下来的m行每行给出a,b,c,表示a点和b点之间有一条桥,而且曹操派了c个人去守卫这条桥。
现在问刘备最少派多少人去炸桥。
如果无法使曹操的点成为多个连通图,则输出-1。
Tips:
①.有重边,所以tarjan算法要处理重边。有两种处理方法,一种是先把所有的边存下,发现两点有重边的时候就只给这两个点连一条权值为无穷大的边。或者是在tarjan算法里处理重边,即使之求u或u的子树能够追溯到的最早的栈中节点的次序号时可访问父节点的次序号。
②. 如果无向图图本身已经有两个连通图了,就无需派人去炸桥,这时候输出0。
③. 如果求出来的最小权值桥的守卫人数为0时,也需要派出一个人去炸桥。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000+100;
const int M = N*N;
const int INF = 0x3f3f3f3f;
int dfn[N],low[N];
struct Node
{
int next,to,w;
Node(){}
Node(int a,int b,int c):next(a),to(b),w(c){}
};
int head[N]; struct Node Edge[M]; int nedges;int ans;int dep;
void add_edge(int a,int b,int c)
{
Edge[++nedges] = Node(head[a],b,c);
head[a] = nedges;
Edge[++nedges] = Node(head[b],a,c);
head[b] = nedges;
}
void dfs(int u,int f)
{
dfn[u] = low[u] = (++dep);
for(int i=head[u];~i;i = Edge[i].next)
{
int v = Edge[i].to;
if(!dfn[v])
{
dfs(v,u);
low[u] = min(low[u],low[v]);
if(low[v]>dfn[u] ) ans = min(ans,Edge[i].w);
}
else if(v!=f)
low[u] = min(low[u],dfn[v]);
}
}
int main()
{
//freopen("data.in","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)!=EOF )
{
if(n==0 && m==0) break;
memset(head,-1,sizeof(head));
nedges = -1;
int u,v,w;
while(m--)
{
scanf("%d%d%d",&u,&v,&w);
bool now = false;
for(int i=head[u];~i;i=Edge[i].next)
{
if(v==Edge[i].to)
{
Edge[i].w = Edge[i^1].w = INF;
now = true;
break;
}
}
if(!now) add_edge(u,v,w);
}
ans = INF;
dep = 0;
memset(dfn,0,sizeof(dfn));
dfs(1,0);
bool flag = true;
for(int i=1;i<=n;i++)
{
if(!dfn[i]) { flag = false; break;}
}
if(!flag) cout<<0<<endl;
else
{
if(ans==INF) cout<<-1<<endl;
else if(ans==0) cout<<1<<endl;
else cout<<ans<<endl;
}
}
return 0;
}