北极的猴子
Time Limit: 1000 MS Memory Limit: 256 MB
Submit Status
也许你不知道,在北极也有猴子,我们叫它们北极猴。北极猴们在北极一共有n个聚落,不妨叫它们1,2,…n号聚落;它们之间有m条双向道路(这意味着如果一条路从1号聚落到2号聚落,那么你可以过这条路从2号聚落到1号聚落),每条道路连接2个聚落,且拥有不同的长度。
不过,由于北极没有多少土地,所以它们之间经常为了争夺领土而开战,由此也产生了许多矛盾。这一天,猴子聚落s和猴子聚落t之间便宣布势不两立,北极联合猴协会调解无效后,它们要求摧毁m条道路中的一些路,使得这两个聚落不能互相到达。
猴子们觉得在北极摧毁道路是一件非常费力的事情,于是它们不希望摧毁两条以上的道路。不过,道路长短不一,所以猴子们希望摧毁的道路的总长度最小。
猴子毕竟只是猴子,它们不会算数,所以它们把选择道路的任务交给了你。
Input
第一行两个整数n,m(2≤ n ≤ 5000, 3 ≤ m ≤5000) 表示北极猴聚落的数量和双向道路的数量。
第二行两个不同的整数s,t ( 1≤ s,t ≤ n),表示势不两立的猴子聚落的编号。
接下来m行,每行三个整数x,y,z,( 1≤ x,y ≤ n, 1 ≤ z ≤ 109109 )表示从x到y有一条距离为z的双向道路。
Output
输出一个或两个整数,表示你选择的道路的编号。如果没有需要删除的道路,则输出0.
道路的编号按照输入顺序,记为1,2,…m.
如果输出两个整数,则它们应该不同,且较小的数在前。
如果有多组满足条件的答案,则输出字典序最小的答案。这意味着,如果答案是a,b,则优先选择a最小的答案;若还是有多组,选择b最小的答案。
如果找不到答案,输出-1.
Sample input and output
Sample Input | Sample Output |
---|---|
5 4 1 5 1 2 3 2 3 1 3 4 4 4 5 2 |
2 |
5 3 1 5 1 2 3 2 3 1 4 5 2 |
0 |
6 7 1 6 2 1 6 2 3 5 3 4 9 4 6 4 4 6 5 4 5 1 3 1 3 |
2 7 |
Hint
样例1:第二条道路的长度为1,且摧毁之后1号聚落和5号聚落不能互相到达。
Source
2018 UESTC ACM Training for Graph Theory
题解:让你找到一条或者两条边,去掉后是的s和t不再联通。如果找不到输出-1.如果有多个按字典序输出;很明显能看出用无向图的桥处理。
1.首先判断s和t是否相连,如果不相连,输出-1.
2.只去掉一条边,判断是否含有无向图的桥存在,如果存在,输出该边;
3.去掉两条边, 我们可以为每一条打上临时标记,然后可以转化为第2种情况;
4.如果去掉两条边也没有,则输出-1.
AC代码为:
#include<bits/stdc++.h> using namespace std; const int INF1=1e8; const int INF2=1e9; struct part{ int to,W,net; } e[10010]; struct part1{ int id,v; } pre[5010],pre1[5010]; int n,m,s,t,min1,min2,dfn[5010],low[5010],st[5010],cnt,num,cut[10010],vis[5010],flag[10010],h[5001][5001]; void addedge(int x,int y,int z) { e[cnt].to=y; e[cnt].W=z; e[cnt].net=st[x]; st[x]=cnt++; } void findcut(int x,int f) { dfn[x]=low[x]=++num; for(int i=st[x];~i;i=e[i].net) { if(!dfn[e[i].to]&&!flag[i]) { findcut(e[i].to,x); low[x]=min(low[x],low[e[i].to]); if (low[e[i].to]>dfn[x]&&h[x][e[i].to]==1) { cut[i]=1; cut[i^1]=1; } } else if(e[i].to!=f && !flag[i]) low[x]=min(low[x],dfn[e[i].to]); } } int bfs(int x,int y) { queue<int> q; memset(vis,0,sizeof(vis)); q.push(x); pre[x].v=x; vis[x]=1; int v=0; while(!q.empty()) { int p=q.front(); q.pop(); for(int i=st[p];~i;i=e[i].net) { if(!vis[e[i].to]) { vis[e[i].to]=true; pre[e[i].to].v=p; pre[e[i].to].id=i; q.push(e[i].to); } if(e[i].to==y) { v=1; break; } } if(v==1) break; } int ans=-1; while(v==1 && y!=x) { if(cut[pre[y].id]==1) { if(e[pre[y].id].W<min1) { min1=e[pre[y].id].W; ans=pre[y].id/2+1; } else if(e[pre[y].id].W==min1&&pre[y].id/2+1<ans) ans=pre[y].id/2+1; } y=pre[y].v; } if(v==0) return 10000; else return ans; } int bfs1(int x,int y) { memset(vis,0,sizeof(vis)); memset(pre1,-1,sizeof(pre1)); queue<int> q; pre1[x].v=x; q.push(x); vis[x]=true; int v=0; while(!q.empty()) { int p=q.front(); q.pop(); for(int i=st[p];~i;i=e[i].net) { if(!vis[e[i].to] && flag[i]==0) { vis[e[i].to]=true; pre1[e[i].to].v=p; pre1[e[i].to].id=i; q.push(e[i].to); } if(e[i].to==y && flag[i]==0) { v=1; break; } } if(v==1) break; } int ans=-1; while(v==1 && y!=x) { if(cut[pre1[y].id]==1) { if(e[pre1[y].id].W<min2) { min2=e[pre1[y].id].W; ans=pre1[y].id/2+1; } else if(e[pre1[y].id].W==min2&&pre1[y].id/2+1<ans) ans=pre1[y].id/2+1; } y=pre1[y].v; } return ans; } int main() { cnt=0; cin>>n>>m>>s>>t; int start=0; for(int i=0;i<=n+1;i++) st[i]=-1; int x,y,z; for(int i=1;i<=m;i++) { cin>>x>>y>>z; h[x][y]+=1; h[y][x]+=1; addedge(x,y,z); addedge(y,x,z); start=x; } memset(dfn,0,sizeof dfn); memset(low,0,sizeof low); num=0; findcut(s,0); min1=INF2; int ans=bfs(s,t); if(ans==10000) { printf("0\n"); return(0); } int ans0=ans; int ans1=INF1,ans2=INF1; int tt=t,vv=0; int min3=INF2; while(tt!=s) { flag[pre[tt].id]=1; flag[pre[tt].id^1]=1; h[pre[tt].v][tt]-=1; h[tt][pre[tt].v]-=1; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(cut,0,sizeof(cut)); findcut(s,0); min2=INF2; ans=bfs1(s,t); if(ans!=-1) { if(min2+e[pre[tt].id].W<min3) { min3=min2+e[pre[tt].id].W; ans1=pre[tt].id/2+1; ans2=ans; if(ans1>ans2) swap(ans1,ans2); } else if(min2+e[pre[tt].id].W==min3) { if(min(ans,pre[tt].id/2+1)<ans1) { ans1=min(pre[tt].id/2+1,ans); ans2=max(pre[tt].id/2+1,ans); } else if(min(pre[tt].id/2+1,ans)==ans1 && max(ans,pre[tt].id/2+1)<ans2) { ans1=min(pre[tt].id/2+1,ans); ans2=max(pre[tt].id/2+1,ans); } if(ans1>ans2) swap(ans1,ans2); } vv=1; } flag[pre[tt].id]=0; flag[pre[tt].id^1]=0; h[pre[tt].v][tt]+=1; h[tt][pre[tt].v]+=1; tt=pre[tt].v; } if(ans0==-1) { if(vv==0) cout<<-1<<endl; else cout<<min(ans1,ans2)<<" "<<max(ans1,ans2)<<endl; } else { if(vv==0) cout<<ans0<<endl; else { if(min1<min3) cout<<ans0<<endl; else cout<<min(ans1,ans2)<<" "<<max(ans1,ans2)<<endl; } } return 0; }