码迷,mamicode.com
首页 > 其他好文 > 详细

Plug It In!(网络流板子)

时间:2019-08-23 10:25:00      阅读:78      评论:0      收藏:0      [点我收藏+]

标签:nec   NPU   rand   避免   sed   flow   网络流   max   一半   

问题 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!(网络流板子)

标签:nec   NPU   rand   避免   sed   flow   网络流   max   一半   

原文地址:https://www.cnblogs.com/sylvia1111/p/11398434.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!