Plug It In!(网络流板子)

Posted sylvia1111

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Plug It In!(网络流板子)相关的知识,希望对你有一定的参考价值。

问题 E: Plug It In!

时间限制: 12 Sec  内存限制: 128 MB

题目描述

Adam just moved into his new apartment and simply placed everything into it at random. This means in particular that he did not put any effort into placing his electronics in a way that each one can have its own electric socket.
Since the cables of his devices have limited reach, not every device can be plugged into every socket without moving it first. As he wants to use as many electronic devices as possible right away without moving stuff around, he now tries to figure out which device to plug into which socket. Luckily the previous owner left behind a plugbar which turns one electric socket into 3. 
Can you help Adam figure out how many devices he can power in total?

 

输入

The input consists of:
• one line containing three integers m, n and k, where
– m (1 ≤ m ≤ 1 500) is the number of sockets;
– n (1 ≤ n ≤ 1 500) is the number of electronic devices;
– k (0 ≤ k ≤ 75 000) is the number of possible connections from devices to sockets.
• k lines each containing two integers xi and yi indicating that socket xi can be used to power device yi .
Sockets as well as electronic devices are numbered starting from 1.
The plugbar has no cable, i.e. if it is plugged into a socket it simply triples it.

 

输出

Output one line containing the total number of electrical devices Adam can power.

 

样例输入

3 6 8
1 1
1 2
1 3
2 3
2 4
3 4
3 5
3 6

样例输出

5

 


 

题意 n个插头,m条电线,有一个 一转三的插座,输出最大可连的设备数;

二分图匹配题;最大匹配数=网络流的最大流;但是一转三的插头,应该通过枚举加一条S到插头点的边,由于图跑一边网络流,就不能再用了,所以要先存起来;

 

  1 #include<bits/stdc++.h>
  2 #define INF LLONG_MAX/2
  3 #define N 80500
  4 using namespace std;
  5  
  6 struct ss
  7 
  8     int v,next;
  9     long long flow;
 10 ;
 11 int head[N],now_edge=0,S,T;
 12 ss edg[N*10];
 13  
 14 ss lsedg[N*10];
 15 int lshead[N],lssum_edge;
 16 void init() //初始化
 17 
 18     now_edge=0;
 19     memset(head,-1,sizeof(head)); 
 20 
 21  
 22 void addedge(int u,int v,long long flow) //加边,加双向边,反向边为0
 23 
 24     edg[now_edge]=(ss)
 25     
 26         v,head[u],flow
 27     ;
 28     head[u]=now_edge++;
 29     edg[now_edge]=(ss)
 30     
 31         u,head[v],0
 32     ;
 33     head[v]=now_edge++;
 34 
 35  
 36 int dis[N];
 37  
 38 int bfs() //这个过程给网络分层,避免循环跑;
 39 
 40     memset(dis,0,sizeof(dis));
 41     queue<int>q;
 42     q.push(S);
 43     dis[S]=1;
 44  
 45     while(!q.empty())
 46     
 47         int now=q.front();
 48         q.pop();
 49  
 50         for(int i=head[now]; i!=-1; i=edg[i].next)
 51         
 52             ss &e=edg[i];
 53             if(e.flow>0&&dis[e.v]==0)
 54             
 55                 dis[e.v]=dis[now]+1;
 56                 q.push(e.v);
 57             
 58         
 59     
 60  
 61     if(dis[T]==0)return 0;
 62     return 1;
 63 
 64  
 65 int current[N];//就是记录了当前搜索到了这个点的哪一条边
 66 long long dfs(int x,long long maxflow)
 67 
 68     if(x==T)return maxflow;
 69     for(int i=current[x]; i!=-1; i=edg[i].next)
 70     
 71         current[x]=i;//然后接下来直接从这个边搜索就行了
 72  
 73         ss &e=edg[i];
 74         if(e.flow>0&&dis[e.v]==dis[x]+1)  //流量大于0,且在下一层
 75         
 76             long long flow=dfs(e.v,min(maxflow,e.flow)); //在最大流和当前流取较小值
 77  
 78             if(flow!=0)
 79             
 80                 e.flow-=flow;
 81                 edg[i^1].flow+=flow;
 82                 return flow;
 83             
 84         
 85     
 86     return 0;
 87 
 88  
 89 long long dinic()
 90 
 91     long long ans=0,flow;
 92  
 93     while(bfs())
 94     
 95         for(int i=0; i<N; i++)current[i]=head[i];
 96         while(flow=dfs(S,INF))ans+=flow;
 97     
 98     return ans;
 99 
100  //以上都是板子,用于求最大流
101 //二分图匹配问题,二分图的每条边权值都是1,二分图最大匹配就是最大流
102 int main()
103 
104     int m,n,k;
105     long long  res=0;
106     scanf("%d%d%d",&m,&n,&k);
107     init();
108     S=n+m+1,T=S+1;
109     for(int i=0; i<k; i++)
110     
111         int u,v;
112         scanf("%d %d",&u,&v);
113         addedge(u,v+m,1); //把u,v都变成不重复的数值
114     
115     for(int i=1; i<=m; i++)
116     
117         addedge(S,i,1); //把起点与二分图的一半连起来
118     
119     for(int i=1; i<=n; i++)
120     
121         addedge(i+m,T,1); //与终点连起来
122     
123     long long nowmax=dinic(); //跑一边最大流
124     long long cancan=0;
125  
126     for(int i=0; i<now_edge; i++)  //将图存起来
127     
128         lsedg[i].flow=edg[i].flow;
129         lsedg[i].next=edg[i].next;
130         lsedg[i].v=edg[i].v;
131     
132     for(int i=0;i<=n+m+2;i++)lshead[i]=head[i]; 
133     lssum_edge=now_edge;
134  
135     for(int i=1; i<=m; i++) //然后手动把图复制,枚举起点到二分图的点,且权值为2
136     
137         now_edge=lssum_edge;
138         for(int i=0; i<now_edge; i++)
139         
140             edg[i].flow=lsedg[i].flow;
141             edg[i].next=lsedg[i].next;
142             edg[i].v=lsedg[i].v;
143         
144         for(int i=0;i<=n+m+2;i++)head[i]=lshead[i];
145  
146         addedge(S,i,2);
147         long long dangqiancancan=dinic();
148  
149         cancan=max(cancan,dangqiancancan);//维护一个最大值
150     
151     printf("%lld\n",cancan+nowmax);
152  
153     return 0;
154 

 

以上是关于Plug It In!(网络流板子)的主要内容,如果未能解决你的问题,请参考以下文章

板子 网络流算法

uva753 A Plug for UNIX 网络流最大流

C - A Plug for UNIX POJ - 1087 网络流

poj1087 A Plug for UNIX(网络流最大流)

POJ1087 A Plug for UNIX(网络流)

COGS 14 [网络流24题] 搭配飞行员 网络流板子题