题目描述:曹操在长江上修了n个岛,m座桥,桥上有一定士兵把守。刘备派人去炸一座桥,使得避免所有岛屿连成一起。要求派出的人不少与桥上把守的士兵,问最少派多少人。
这是裸的割顶(割点)、割桥问题,找出所有的割桥,求最小值即可。
坑点:
1、重边问题,判断如果“割桥”有重边,那么其实不是割桥,不能考虑。
2、有可能一开始就不是所有的岛连接在一起,则不需要派人。
3、当割桥上士兵为0时,要派一个人去炸桥。
试验证明,以上情况都会出现,为我的漏洞百出的思维感到忧伤。。。。
代码:
#include<bits/stdc++.h>
#define N 1000+10
#define mem(f,n) memset(f,n,sizeof f)
using namespace std;
int low[N],pre[N],fr[N],i,j,k,l,n,m,t,h,cnt,dfs_clock,Ans;
short int vis[N][N];
bool iscut[N];
struct edge{ int u,w,la; }G[200010];
int min(int a,int b) {return a>b?b:a;}
void addedge(int u,int v,int k)
{
G[++cnt].u=v;
G[cnt].w=k;
G[cnt].la=fr[u];
fr[u]=cnt;
}
int dfs(int u,int fa)
{
int lowu=pre[u]=++dfs_clock;
int child=0;
for (int i=fr[u];i;i=G[i].la)
{
int v=G[i].u;
if (!pre[v])
{
child++;
int lowv=dfs(v,u);
lowu=min(lowu,lowv);
if (lowv>pre[u]) //割桥
{
if (vis[u][v]>1)continue;
Ans=min(Ans,G[i].w);
}
}
else if (pre[v]<pre[u] && v!=fa)
{
lowu=min(lowu,pre[v]);
}
}
if (fa<0 && child==1) iscut[u]=0;
low[u]=lowu;
return lowu;
}
int main()
{
while (~scanf("%d%d",&n,&m)&& n>0)
{
Ans=1e7;
dfs_clock=cnt=0;
mem(pre,0);
mem(G,0);
mem(fr,0);
mem(vis,0);
for (i=1;i<=m;i++)
{
int l;
scanf("%d%d%d",&j,&k,&l);
addedge(j,k,l); vis[j][k]++;
addedge(k,j,l); vis[k][j]++;
}
dfs(1,-1);
if (dfs_clock<n)cout<<0<<endl;else
if (Ans==10000000)puts("-1");else
{
if (Ans==0)cout<<1<<endl;else cout<<Ans<<endl;
}
}
return 0;
}