【BZOJ 4663】 (最小割)
4663: Hack
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 69 Solved: 26Description
由于 FZYZ 教学区禁止使用手机,所以如何在一个课间通知到人就成了一个很大的问题。所幸,在不知道被信息传递不及时坑了多少次之后,小叶子(@97littleleaf11)完美地解决了这个问题。小叶子组建了一张关系网,每一个人是这张关系网上的一个节点(节点编号为[0,n-1]),两个人之间的通讯关系就是这张网上的一条有向边(一条 u->v 的边意味着信息可以从u 传递到 v)。小叶子是 0 号节点,也是信息的发出者,n+e 是 n-1 号节点,在这个问题中,他就是信息的接受者。一条信息从小叶子出发,可以沿着任意的边传递,最终传递给 n+e。在这个过程中,一个人(包括小叶子和 n+e)可以经过多次,一条边也可以经过多次。经过多年的观察,小叶子发现这张关系网的每一条边都是有可能被hack 的!当然每条边 hack 的代价是不一样的。所以,小叶子想要评价这个关系网的安全程度。试想你要入侵这一张关系网,那么你只能事先选择一些边,将这些边hack 掉。如果一条边被 hack 了,就意味着当信息从这条边传递的时候就会被截获。当然 n+e 也是非常厉害的!如果一条信息在传递过程中被截获两次及以上,那么 n+e 就能用强大的智商定位出你的位置,那么这一次入侵就必然会失败。当然,如果 n+e 接收到了消息,但是这条消息没有被截获,那么这次入侵也就是失败的。更精确地说,一次成功的入侵要满足以下条件:对于任意一种可能的传递信息的方式(对应着一条从 0 到 n-1 的路径),必须经过恰好一次被hack 的边。一次入侵的代价就是你选择 hack 掉的边的代价和。小叶子想要知道,如果你拥有 n+e 这样超神的智商,而你又想最小化代价,那么你入侵的代价会是多少呢?Input
第一行 n,m。表示点数及边数接下来 m 行,每行三个整数 u,v,w,表示一条从 u 到 v 的代价为 w 的边。2<=n<=100,m<=2500,1<=w<=10^9,0<=u,v<n,保证存在至少一条从0到n-1的路径。Output
输出一行,表示答案。,如果不存在合法的入侵方案,那么输出-1.Sample Input
6 7
0 1 5
0 2 5
1 3 1
2 4 1
4 1 1
3 5 5
4 5 5Sample Output
6
//hack 掉 0->1,2->4 这两条边HINT
Source
【分析】
其实反向边建INF的想法有考虑过。但是不会证。很迷人。。。
送个迷人的图:
就是建了inf反向边,就不会同一路径的割了,因为并不会更好。。
然后要注意删掉st到不了的点,不然会有这样迷人的情况:
st本来不会经过a到ed,但现在这样建INF,就一定要割掉一些边断掉它了。

1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<stack> 8 using namespace std; 9 #define Maxn 110 10 #define Maxm 2600 11 #define LL long long 12 const LL INF=(LL)3000*(LL)1e9; 13 14 LL mymin(LL x,LL y) {return x<y?x:y;} 15 16 struct node{int x,y,o,next;LL f;bool p;}t[Maxm*2]; 17 bool vis[Maxn]; 18 int first[Maxn],len; 19 20 void ins(int x,int y,LL f) 21 { 22 t[++len].x=x;t[len].y=y;t[len].f=f; 23 t[len].next=first[x];first[x]=len;t[len].o=len+1; 24 t[++len].x=y;t[len].y=x;t[len].f=INF; 25 t[len].next=first[y];first[y]=len;t[len].o=len-1; 26 t[len-1].p=t[len].p=1; 27 } 28 29 void dfs(int x) 30 { 31 vis[x]=1; 32 for(int i=first[x];i;i=t[i].next) 33 { 34 if(i%2==0) continue; 35 int y=t[i].y; 36 if(!vis[y]) dfs(y); 37 } 38 } 39 40 int st,ed; 41 int dis[Maxn]; 42 queue<int > q; 43 bool bfs() 44 { 45 for(int i=1;i<=ed;i++) dis[i]=-1; 46 while(!q.empty()) q.pop(); 47 dis[st]=0;q.push(st); 48 while(!q.empty()) 49 { 50 int x=q.front(); 51 for(int i=first[x];i;i=t[i].next) if(t[i].p&&t[i].f>0) 52 { 53 int y=t[i].y; 54 if(!vis[y]) continue; 55 if(dis[y]==-1) 56 { 57 dis[y]=dis[x]+1; 58 q.push(y); 59 } 60 } 61 q.pop(); 62 } 63 if(dis[ed]==-1) return 0; 64 return 1; 65 } 66 67 LL ffind(int x,LL flow) 68 { 69 if(x==ed) return flow; 70 LL now=0; 71 for(int i=first[x];i;i=t[i].next) if(t[i].p&&t[i].f>0) 72 { 73 int y=t[i].y; 74 if(dis[y]==dis[x]+1) 75 { 76 LL a=ffind(y,mymin(flow-now,t[i].f)); 77 t[i].f-=a; 78 t[t[i].o].f+=a; 79 now+=a; 80 } 81 if(now==flow) break; 82 } 83 if(now==0) dis[x]=-1; 84 return now; 85 } 86 87 void output() 88 { 89 for(int i=1;i<=len;i++) if(t[i].p) 90 { 91 printf("%d -> %d %d\n",t[i].x,t[i].y,t[i].f); 92 }printf("\n"); 93 } 94 95 LL ans=0; 96 void max_flow() 97 { 98 while(bfs()) 99 { 100 ans+=ffind(st,INF); 101 if(ans>=INF) break; 102 } 103 } 104 105 int main() 106 { 107 int n,m; 108 scanf("%d%d",&n,&m); 109 len=0; 110 memset(first,0,sizeof(first)); 111 for(int i=1;i<=m;i++) 112 { 113 int x,y;LL f; 114 scanf("%d%d%lld",&x,&y,&f); 115 x++;y++; 116 ins(x,y,f); 117 } 118 for(int i=1;i<=n;i++) vis[i]=0;vis[1]=1; 119 dfs(1); 120 for(int i=1;i<=len;i+=2) if(vis[t[i].x]==0) t[i].p=t[t[i].o].p=0; 121 st=1;ed=n; 122 // output(); 123 max_flow(); 124 if(ans>=INF) printf("-1\n"); 125 else printf("%lld\n",ans); 126 return 0; 127 }
2017-03-31 08:26:56