poj 2125(最小割)

题目链接:http://poj.org/problem?id=2125

思路:将最小点权覆盖转化为最小割模型,于是拆点建图,将点i拆成i,i+n,其中vs与i相连,边容量为w[i]-,i+n与vt相连,边容量为w[i]+,如果i,j有边相连,则i与j+n连边inf.从而跑最大流求解。对于输出解决放案,我们可以在残余网络中进行dfs,从vs出发,对于那些i<=n没有遍历到的点,说明被取走了,输出‘-’,对于那些i>n遍历到的点,说明之前有j->i的边(j<=n),vs->j不是最小割中的边,i是最小割中的点,输出‘+’。

copy一张图:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 #define MAXN 222
  8 #define MAXM 2222222
  9 #define inf 1<<30
 10 
 11 struct Edge{
 12     int v,cap,next;
 13 }edge[MAXM];
 14 
 15 int n,m,NE,vs,vt,NV;
 16 int head[MAXN];
 17 
 18 void Insert(int u,int v,int cap)
 19 {
 20     edge[NE].v=v;
 21     edge[NE].cap=cap;
 22     edge[NE].next=head[u];
 23     head[u]=NE++;
 24 
 25     edge[NE].v=u;
 26     edge[NE].cap=0;
 27     edge[NE].next=head[v];
 28     head[v]=NE++;
 29 }
 30 
 31 int from[MAXN],to[MAXN];
 32 bool map[MAXN][MAXN];
 33 
 34 void Build()
 35 {
 36     NE=0;
 37     memset(head,-1,sizeof(head));
 38     vs=0,vt=2*n+1,NV=2*n+2;
 39     for(int i=1;i<=n;i++){
 40         Insert(vs,i,to[i]);
 41         Insert(i+n,vt,from[i]);
 42         for(int j=1;j<=n;j++){
 43             if(map[i][j])Insert(i,j+n,inf);
 44         }
 45     }
 46 }
 47 
 48 int level[MAXN],gap[MAXN];
 49 void bfs(int vt)
 50 {
 51     memset(level,-1,sizeof(level));
 52     memset(gap,0,sizeof(gap));
 53     level[vt]=0;
 54     gap[level[vt]]++;
 55     queue<int>que;
 56     que.push(vt);
 57     while(!que.empty()){
 58         int u=que.front();
 59         que.pop();
 60         for(int i=head[u];i!=-1;i=edge[i].next){
 61             int v=edge[i].v;
 62             if(level[v]<0){
 63                 level[v]=level[u]+1;
 64                 gap[level[v]]++;
 65                 que.push(v);
 66             }
 67         }
 68     }
 69 }
 70 
 71 int cur[MAXN],pre[MAXN];
 72 
 73 int SAP(int vs,int vt)
 74 {
 75     bfs(vt);
 76     memset(pre,-1,sizeof(pre));
 77     memcpy(cur,head,sizeof(head));
 78     int maxflow=0,aug=inf;
 79     int u=pre[vs]=vs;
 80     gap[0]=NV;
 81     while(level[vs]<NV){
 82         bool flag=false;
 83         for(int &i=cur[u];i!=-1;i=edge[i].next){
 84             int v=edge[i].v;
 85             if(edge[i].cap>0&&level[u]==level[v]+1){
 86                 flag=true;
 87                 pre[v]=u;
 88                 u=v;
 89                 aug=min(aug,edge[i].cap);
 90                 if(v==vt){
 91                     maxflow+=aug;
 92                     for(u=pre[v];v!=vs;v=u,u=pre[u]){
 93                         edge[cur[u]].cap-=aug;
 94                         edge[cur[u]^1].cap+=aug;
 95                     }
 96                     aug=inf;
 97                 }
 98                 break;
 99             }
100         }
101         if(flag)continue;
102         int minlevel=NV;
103         for(int i=head[u];i!=-1;i=edge[i].next){
104             int v=edge[i].v;
105             if(edge[i].cap>0&&level[v]<minlevel){
106                 minlevel=level[v];
107                 cur[u]=i;
108             }
109         }
110         if(--gap[level[u]]==0)break;
111         level[u]=minlevel+1;
112         gap[level[u]]++;
113         u=pre[u];
114     }
115     return maxflow;
116 }
117 
118 bool mark[MAXN];
119 void dfs(int u)
120 {
121     mark[u]=true;
122     for(int i=head[u];i!=-1;i=edge[i].next){
123         int v=edge[i].v;
124         if(!mark[v]&&edge[i].cap>0)dfs(v);
125     }
126 }
127 
128 
129 int main()
130 {
131 //   freopen("1.txt","r",stdin);
132     int u,v,cnt;
133     while(~scanf("%d%d",&n,&m)){
134         for(int i=1;i<=n;i++)scanf("%d",&from[i]);
135         for(int i=1;i<=n;i++)scanf("%d",&to[i]);
136         memset(map,false,sizeof(map));
137         while(m--){
138             scanf("%d%d",&u,&v);
139             map[u][v]=true;
140         }
141         Build();
142         printf("%d\n",SAP(vs,vt));
143         memset(mark,false,sizeof(mark));
144         dfs(vs);
145         cnt=0;
146         for(int i=1;i<=2*n;i++){
147             if(!mark[i]&&i<=n)cnt++;
148             else if(mark[i]&&i>n)cnt++;
149         }
150         printf("%d\n",cnt);
151         for(int i=1;i<=2*n;i++){
152             if(!mark[i]&&i<=n)printf("%d -\n",i);
153             else if(mark[i]&&i>n)printf("%d +\n",i-n);
154         }
155     }
156     return 0;
157 }
View Code

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值