CF700C (枚举+tarjan)

Problem Break up (CF700C)

题目大意

  给一张n个点,m条边的无向图,有边权,和起点S,终点T。 (n<=1000 , m<=30000)

  要求最多割掉2条边,使得S到T不连通。

  输出最小代价以及方案。

解题分析

  如果只是割掉1条边,那么就是求割边了。

  如果要割掉2条边,一个自然的思路就是枚举一条边后再求割点,这样复杂度是O(m ^2)的,显然会超时。

  再考虑并不需要枚举每一条边,只需要求一条S到T的路径,枚举这条路径上的边即可。因为若要不连通,必定要割掉这条路径上的某一条边

  复杂度O(n*m)。

参考程序

  1 #include <map>
  2 #include <set>
  3 #include <stack>
  4 #include <queue>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <string>
  8 #include <vector>
  9 #include <cstdio>
 10 #include <cstdlib>
 11 #include <cstring>
 12 #include <iostream>
 13 #include <algorithm>
 14 #pragma comment(linker,"/STACK:102400000,102400000")
 15 using namespace std;
 16 
 17 #define     N             100008             
 18 #define     V             1008
 19 #define        E            60008    
 20 #define        lson        l,m,rt<<1
 21 #define     rson        m,r+1,rt<<1|1
 22 #define        clr(x,v)    memset(x,v,sizeof(x));
 23 #define        LL            long long 
 24 
 25 const int    mo    =    1000000007;
 26 const int     inf =    0x3f3f3f3f;
 27 const int     INF =    2000000008;
 28 /**************************************************************************/ 
 29 
 30 int n,m,S,T,tmp;
 31 int vis[V],path[V],dfn[V],low[V],road[V],bridge[E];
 32 int ans;
 33 int ANS[V];
 34 struct line{
 35     int u,v,w,nt;
 36 }eg[E];
 37 int sum,lt[V];
 38 
 39 
 40 void adt(int u,int v,int w){
 41     eg[++sum]=(line){u,v,w,lt[u]};
 42     lt[u]=sum;
 43 }
 44 void add(int u,int v,int w){
 45     adt(u,v,w); adt(v,u,w);
 46 }
 47 
 48 bool dfs(int u){
 49     vis[u]=1;
 50     if (u==T) return true; 
 51     for (int i=lt[u];i;i=eg[i].nt){
 52         int v=eg[i].v;
 53         if (vis[v]) continue;
 54         if (dfs(v)){
 55             path[++path[0]]=i/2;
 56             return true;
 57         }
 58     }
 59     return false;
 60 }
 61 
 62 bool dfs_2(int u,int del){
 63     vis[u]=1;
 64     if (u==T) return true;
 65     for (int i=lt[u];i;i=eg[i].nt){
 66         int v=eg[i].v;
 67         if (i/2==del) continue;
 68         if (vis[v]) continue;
 69         if (dfs_2(v,del)){
 70             road[++road[0]]=i/2;
 71             return true;
 72         }
 73     }
 74     return false;
 75 }
 76 void tarjan(int u,int fa,int del){
 77     dfn[u]=low[u]=++tmp;
 78     int flag=0;
 79     for (int i=lt[u];i;i=eg[i].nt){
 80         int v=eg[i].v;
 81         if (i/2==del) continue;
 82         if (v==fa && !flag){
 83             flag=1;
 84             continue;
 85         }
 86         if (!dfn[v]){
 87             tarjan(v,u,del);
 88             low[u]=min(low[u],low[v]);
 89             if (dfn[u]<low[v]) bridge[i/2]=1;
 90         }
 91         else low[u]=min(low[u],dfn[v]);
 92     }
 93 }
 94 
 95 int main(){
 96     scanf("%d %d",&n,&m);
 97     scanf("%d %d",&S,&T);
 98     sum=1;
 99     for (int i=1;i<=m;i++){
100         int u,v,w;
101         scanf("%d %d %d",&u,&v,&w);
102         add(u,v,w);
103     }
104 
105     clr(vis,0); 
106     clr(path,0);
107     if (!dfs(S)) { printf("0\n0\n"); return 0; }
108     else
109     {    
110         ans=INF;
111         for (int ii=1;ii<=path[0];ii++){
112             clr(bridge,0);
113             clr(vis,0);
114             clr(road,0);
115             clr(dfn,0);
116             tmp=0;             
117             for (int i=1;i<=n;i++)
118                 if (!dfn[i])
119                     tarjan(i,0,path[ii]);
120             if (!dfs_2(S,path[ii])){
121                 if (eg[path[ii]*2].w<ans){
122                     ans = eg[path[ii]*2].w;
123                     ANS[0]=1;
124                     ANS[1]=path[ii];
125                 }
126             }
127             else
128             {
129                 for (int i=1;i<=road[0];i++){
130                     if (bridge[road[i]]){
131                         if (eg[road[i]*2].w+eg[path[ii]*2].w<ans){
132                             ans=eg[road[i]*2].w+eg[path[ii]*2].w;
133                             ANS[0]=2;
134                             ANS[1]=road[i];
135                             ANS[2]=path[ii];
136                         }
137                     }
138                 }
139             }
140         }
141         if (ans==INF) printf("-1\n");
142         else
143         {
144             printf("%d\n%d\n",ans,ANS[0]);
145             for (int i=1;i<=ANS[0];i++) printf("%d%c",ANS[i],i!=ANS[0]?' ':'\n');
146         }
147     }    
148 }
View Code

 

posted @ 2016-08-05 16:41  rpSebastian  阅读(343)  评论(0编辑  收藏  举报