POJ 2125 - Destroying The Graph 构图最小割

                 题意:

                          给了一个有向图..并且告诉一次性去掉所有以某点为终点的边的代价..一次性去掉所有以某点为起点的边的代价..问最少需要多少代价使得图中没有边..

                 题解:

                         将每个点拆成入度点和出度点..超级源点向所有的出度点做边. .容量为其代价..所有的入度点往超级汇点做边..容量为其代价..然后就是根据边..所有边起始点的出度点向终点的入度点做有向边.容量为无穷大..然后跑最大流求出最小割就是答案....

                         而要找是去掉了哪些点的哪些边..从起点开始dfs染色..容量为空的不过去..然后再扫描所有的边(注意..构造的反向边不要扫描)...找出起点被标记.终点未被标记..并且其容量为0的..这就是割边..根据顶点可以推断出是属于哪个点的那种状态...


Program:

#include<iostream>    
#include<algorithm>    
#include<stdio.h>    
#include<string.h>  
#include<time.h> 
#include<map> 
#include<math.h>    
#include<queue>    
#define MAXN 305 
#define MAXM 50005 
#define oo 1000000007    
#define ll long long    
using namespace std;   
struct Dinic              
{              
       struct node            
       {             
             int c,u,v,next;            
       }edge[MAXM];            
       int ne,head[MAXN];            
       int cur[MAXN], ps[MAXN], dep[MAXN];          
       void initial()            
       {            
             ne=2;            
             memset(head,0,sizeof(head));             
       }            
       void addedge(int u, int v,int c)            
       {             
             edge[ne].u=u,edge[ne].v=v,edge[ne].c=c,edge[ne].next=head[u];            
             head[u]=ne++;            
             edge[ne].u=v,edge[ne].v=u,edge[ne].c=0,edge[ne].next=head[v];            
             head[v]=ne++;            
       }            
       int MaxFlow(int s,int t)            
       {                                 
             int tr, res = 0;            
             int i,j,k,f,r,top;            
             while(1)            
             {            
                    memset(dep, -1, sizeof(dep));            
                    for(f=dep[ps[0]=s]=0,r=1;f!= r;)            
                       for(i=ps[f++],j=head[i];j;j=edge[j].next)            
                         if(edge[j].c&&dep[k=edge[j].v]==-1)            
                         {            
                               dep[k]=dep[i]+1;            
                               ps[r++]=k;            
                               if(k == t){  f=r; break;  }            
                         }            
                    if(dep[t]==-1) break;            
                    memcpy(cur,head,sizeof(cur));            
                    i=s,top=0;            
                    while(1)            
                    {            
                         if(i==t)            
                         {            
                               for(tr=oo,k=0;k<top;k++)            
                                  if(edge[ps[k]].c<tr)            
                                     tr=edge[ps[f=k]].c;            
                               for(k=0;k<top;k++)            
                               {            
                                     edge[ps[k]].c-=tr;            
                                     edge[ps[k]^1].c+=tr;            
                               }            
                               i=edge[ps[top=f]].u;            
                               res+= tr;            
                         }            
                         for(j=cur[i];cur[i];j=cur[i]=edge[cur[i]].next)             
                             if(edge[j].c && dep[i]+1==dep[edge[j].v]) break;             
                         if(cur[i])  ps[top++]=cur[i],i=edge[cur[i]].v;             
                         else            
                         {            
                                 if(!top) break;            
                                 dep[i]=-1;            
                                 i=edge[ps[--top]].u;            
                         }            
                   }            
             }            
             return res;            
      }   
      bool mark[MAXN];
      void dfs(int x)
      {
              mark[x]=true;
              for (int k=head[x];k;k=edge[k].next)
                  if (!mark[edge[k].v] && edge[k].c) dfs(edge[k].v);
      }
      void getans(int s,int e,int &num,int *ans)
      {
              num=0;
              memset(mark,false,sizeof(mark));
              dfs(s);
              for (int i=2;i<=ne;i+=2) // 注意扫描的是建造的边.不要扫描建造的反向边
                if (mark[edge[i].u] && !mark[edge[i].v] && !edge[i].c)
                  if (edge[i].u==s) ans[++num]=edge[i].v;
                              else  ans[++num]=edge[i].u;
      }    
}T;       
int ans[MAXN],num; 
int main()   
{      
      int n,m,s,e,c,u,v,i; 
      while (~scanf("%d%d",&n,&m))
      {
              s=(n<<1)+5,e=s+1,T.initial();
              for (i=1;i<=n;i++) scanf("%d",&c),T.addedge(i<<1|1,e,c);
              for (i=1;i<=n;i++) scanf("%d",&c),T.addedge(s,i<<1,c);
              while (m--)
              {
                      scanf("%d%d",&u,&v);
                      T.addedge(u<<1,v<<1|1,oo);
              }
              printf("%d\n",T.MaxFlow(s,e));
              T.getans(s,e,num,ans);
              sort(ans+1,ans+1+num);
              printf("%d\n",num);
              for (i=1;i<=num;i++) 
                if (ans[i]%2) printf("%d +\n",ans[i]>>1);
                         else printf("%d -\n",ans[i]>>1); 
      }
      return 0;  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值