BZOJ1797:[AHOI2009]最小割(最小割)

Description

A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci。现在B国想找出一个路径切断方案,使中转站s不能到达中转站t,并且切断路径的代价之和最小。 小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题: 问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 现在请你回答这两个问题。

Input

第一行有4个正整数,依次为N,M,s和t。第2行到第(M+1)行每行3个正 整数v,u,c表示v中转站到u中转站之间有单向道路相连,单向道路的起点是v, 终点是u,切断它的代价是c(1≤c≤100000)。 注意:两个中转站之间可能有多条道路直接相连。 同一行相邻两数之间可能有一个或多个空格。

Output

对每条单向边,按输入顺序,依次输出一行,包含两个非0即1的整数,分 别表示对问题一和问题二的回答(其中输出1表示是,输出0表示否)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

Sample Input

6 7 1 6
1 2 3
1 3 2
2 4 4
2 5 1
3 5 5
4 6 2
5 6 3

Sample Output

1 0
1 0
0 0
1 0
0 0
1 0
1 0

HINT

设第(i+1)行输入的边为i号边,那么{1,2},{6,7},{2,4,6}是仅有的三个最小代价切割方案。它们的并是{1,2,4,6,7},交是 。 【数据规模和约定】 测试数据规模如下表所示 数据编号 N M 数据编号 N M 1 10 50 6 1000 20000 2 20 200 7 1000 40000 3 200 2000 8 2000 50000 4 200 2000 9 3000 60000 5 1000 20000 10 4000 60000

Solution

之前做过一道二分图残留网络上跑tarjan的题,
但当时为了应付作业并没有很深入的研究
为了这个题还重新去看了下最大流最小割定理
https://blog.csdn.net/w417950004/article/details/50538948
既然属于最小割集的边一定是满流的(为什么我之前学网络流的时候没看到这个性质……)
我们将原图tarjan缩点,剩下的一定只有满流边。(因为未满流的边(u,v)的正反向边和u点v点本来就可以缩一个点)
那么我们在缩点后的图上随手一割就是一个最小割(因为砍的都是满流边啊)
1、若u,v不属于同一个强连通分量,那么他们可以出现在某个最小割集中(因为两点如果在同一个强连通分量里面他们就已经作为不符合的被缩掉了)
2、若s和u属于同一个强连通分量,v和e属于同一个强连通分量,那么边(u,v)必须砍掉,否则可以继续增广

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<queue>
  5 #define N (5010)
  6 using namespace std;
  7 
  8 struct node{int from,to,next,flow;}edge[N<<6];
  9 int n,m,s,e,u,v,l;
 10 int head[N],num_edge;
 11 int Dfn[N],vis[N],Low[N],Color[N];
 12 int dfs_num,col_num;
 13 int Depth[N],stack[N],top;
 14 queue<int>q;
 15 
 16 void add(int u,int v,int l)
 17 {
 18     edge[++num_edge].to=v;
 19     edge[num_edge].from=u;
 20     edge[num_edge].next=head[u];
 21     edge[num_edge].flow=l;
 22     head[u]=num_edge;
 23 }
 24 
 25 void Tarjan(int x)
 26 {
 27     Dfn[x]=Low[x]=++dfs_num;
 28     vis[x]=true;
 29     stack[++top]=x;
 30     for (int i=head[x];i;i=edge[i].next)
 31         if (edge[i].flow)
 32         {
 33             if (!Dfn[edge[i].to])
 34             {
 35                 Tarjan(edge[i].to);
 36                 Low[x]=min(Low[x],Low[edge[i].to]);
 37             }
 38             else
 39                 if (vis[edge[i].to])
 40                     Low[x]=min(Low[x],Dfn[edge[i].to]);
 41         }
 42     if (Dfn[x]==Low[x])
 43     {
 44         vis[x]=false;
 45         Color[x]=++col_num;
 46         while (stack[top]!=x)
 47         {
 48             vis[stack[top]]=false;
 49             Color[stack[top--]]=col_num;
 50         }
 51         top--;
 52     }
 53 }
 54 
 55 bool Bfs(int s,int e)
 56 {
 57     memset(Depth,0,sizeof(Depth));
 58     q.push(s);
 59     Depth[s]=1;
 60     while (!q.empty())
 61     {
 62         int x=q.front();
 63         q.pop();
 64         for (int i=head[x]; i!=0; i=edge[i].next)
 65             if (!Depth[edge[i].to] && edge[i].flow>0)
 66             {
 67                 Depth[edge[i].to]=Depth[x]+1;
 68                 q.push(edge[i].to);
 69             }
 70     }
 71     return Depth[e];
 72 }
 73 
 74 int Dfs(int x,int low)
 75 {
 76     int Min,f=0;
 77     if (x==e || low==0)
 78         return low;
 79     for (int i=head[x]; i!=0; i=edge[i].next)
 80         if (edge[i].flow>0 && Depth[edge[i].to]==Depth[x]+1 && (Min=Dfs(edge[i].to,min(low,edge[i].flow))))
 81         {
 82             edge[i].flow-=Min;
 83             edge[((i-1)^1)+1].flow+=Min;
 84             low-=Min;
 85             f+=Min;
 86             if (low==0) return f;
 87         }
 88     if (!f) Depth[x]=-1;
 89     return f;
 90 }
 91 
 92 int Dinic(int s,int e)
 93 {
 94     int Ans=0;
 95     while (Bfs(s,e))
 96         Ans+=Dfs(s,0x7fffffff);
 97     return Ans;
 98 }
 99 
100 int main()
101 {
102     scanf("%d%d%d%d",&n,&m,&s,&e);
103     for (int i=1;i<=m;++i)
104     {
105         scanf("%d%d%d",&u,&v,&l);
106         add(u,v,l); add(v,u,0);
107     }
108     Dinic(s,e);
109     for (int i=1;i<=n;++i)
110         if (!Dfn[i])
111             Tarjan(i);
112     for (int i=1;i<=num_edge;i+=2)
113         if (edge[i].flow)
114             printf("0 0\n");
115         else
116         {
117             if (Color[edge[i].from]!=Color[edge[i].to]) printf("1 ");
118             else printf("0 ");
119             if (Color[edge[i].from]==Color[s] && Color[edge[i].to]==Color[e]) printf("1\n");
120             else printf("0\n");
121         }
122 }
posted @ 2018-04-11 19:05  Refun  阅读(283)  评论(0编辑  收藏  举报