题意:n个点,m条无向边,每个边有权值,给你 s 和 t,问你至多删除两条边,让s,t不连通,问方案的权值和最小为多少,并且输出删的边
分析:n<=1000,m是30000 s,t有4种情况(首先定义完全不相同的路径,即两条路径上没有一条边是一样的)
1. s,t本就不连通,输出0即可
2. s,t连通但是只有一条完全不相同的路径
3. s,t连通但是只有两条条完全不相同的路径
4. s,t连通但是有>=3条完全不相同的路径(这种情况无解)
情况1预处理即可,要解决的问题是2,3,4乍一看,情况很多,其实可以用枚举法
首先找出一条从s到t的路径,发现s到t,如果不连通,必须删除这条路径中一条边
于是可以枚举删除的第一条边,剩下的做边双缩点,这时分开讨论
(1)删边后,s和t在一个双连通分量,此时符合上述情况4,无解
(2)本身就不连通,这时只删除枚举的边就好了
(3)连通的话,找到s连通分量到t连通分量中最小的桥就好了,删除的是枚举的边和最小的桥边
最终把合法的方案取最小即可
#include <cstdio> #include <vector> #include <stack> #include <cstring> #include <algorithm> using namespace std; const int N = 1e3+5; const int INF = 1e9+7; typedef long long LL; int s,t,n,m; int a[N*30],b[N*30],c[N*30]; vector<int>g[N]; bool ban[30*N]; int dfn[N],low[N],clk,bel[N],cnt; stack<int>st; void targin(int u,int f){ dfn[u]=low[u]=++clk; bool flag=0;st.push(u); for(int i=0;i<g[u].size();++i){ if(ban[g[u][i]])continue; int v=u==a[g[u][i]]?b[g[u][i]]:a[g[u][i]]; if(v==f&&!flag){flag=1;continue;} if(!dfn[v]){ targin(v,u); low[u]=min(low[u],low[v]); } else low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ ++cnt;int x; do{ x=st.top(); st.pop(); bel[x]=cnt; }while(x!=u); } } int path[N*2]; int vis[N]; bool find_pre(int u,int d){ vis[u]=d; if(u==t)return true; for(int i=0;i<g[u].size();++i){ int v=u==a[g[u][i]]?b[g[u][i]]:a[g[u][i]]; if(vis[v])continue; path[d]=g[u][i]; if(find_pre(v,d+1))return true; } return false; } vector<int>G[N]; int find_brige(int u,int f,int id){ if(bel[t]==u)return id; for(int i=0;i<G[u].size();++i){ int x=bel[a[G[u][i]]],y=bel[b[G[u][i]]]; int v=u==x?y:x; if(v==f)continue; int tmp=id;if(c[G[u][i]]<c[id])tmp=G[u][i]; tmp=find_brige(v,u,tmp); if(tmp)return tmp; } return 0; } int main(){ c[0]=INF; scanf("%d%d%d%d",&n,&m,&s,&t); for(int i=1;i<=m;++i){ scanf("%d%d%d",&a[i],&b[i],&c[i]); if(a[i]!=b[i]) g[a[i]].push_back(i),g[b[i]].push_back(i); } if(!find_pre(s,1)){printf("0 0 ");return 0;} int ans1=-1,id; int ans2=-1,id1,id2; for(int i=1;i<vis[t];++i){ ban[path[i]]=true; memset(dfn,0,sizeof(dfn));cnt=clk=0; for(int j=1;j<=n;++j)if(!dfn[j])targin(j,0); if(bel[s]==bel[t]){ban[path[i]]=false;continue;} for(int j=0;j<N;++j)G[j].clear(); for(int j=1;j<=m;++j){ if(ban[j]||bel[a[j]]==bel[b[j]])continue; G[bel[a[j]]].push_back(j); G[bel[b[j]]].push_back(j); } int cur=find_brige(bel[s],0,0); if(!cur){ if(ans1==-1||ans1>c[path[i]]) ans1=c[path[i]],id=path[i]; } else{ if(ans2==-1||ans2>c[path[i]]+c[cur]){ ans2=c[path[i]]+c[cur]; id1=cur;id2=path[i]; } } ban[path[i]]=false; } if(ans1==-1&&ans2==-1)printf("-1 "); else if(ans1!=-1&&ans2==-1){ printf("%d 1 %d ",ans1,id); } else if(ans1==-1&&ans2!=-1){ printf("%d 2 %d %d ",ans2,id1,id2); } else{ if(ans1<=ans2)printf("%d 1 %d ",ans1,id); else printf("%d 2 %d %d ",ans2,id1,id2); } return 0; }