uva 753(最大流)

题意:有若干个电器设备需要不同的适配器才能接上电源,现在你要让尽可能多的电气设备接上电源。首先你手中有n个适配器和适配器的型号,再告诉你有m个电器和他们分别对应的适配器的型号,最后还有一个商店提供买不同型号的适配器转换器,转换是单向的A B表示能把A接口转换成B接口(就是原来需要用A适配器的现在可以用B适配器当然也可以用原来的不变)超市提供的转换器数量是没有限制的,可以无限买。

思路:这道题很容易就转化为最大流问题首先一个源点连接不同的电器流量为1,不同的电器根据需要连上不同的适配器流量也为1,再根据不同适配器中能转换建立流量为INF的单向边,再根据每个每个适配器拥有的数量从没个适配器连接一条流量为其数量的边至汇点。这样图就建完了,接下来是EK算法解决问题。

代码如下:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <stack>
  8 #include <utility>
  9 #define LEN 510
 10 #define INF 0x3f3f3f3f
 11 #define ll long long
 12 #define eps 1e-6
 13  
 14 using namespace std;
 15  
 16 int n, m, k, tn, tm, tk, cap[LEN][LEN];
 17 char rec[LEN][51], di[LEN][51], numr[LEN];
 18  
 19 void init(){
 20     tn = tm = tk = 0;
 21     memset(numr, 0, sizeof numr);
 22     memset(cap, 0, sizeof cap);
 23 }
 24  
 25 int ji(char str[]){
 26     for(int i=0; i<tn; i++){
 27         if(strcmp(rec[i], str)==0)return i;
 28     }
 29     return -1;
 30 }
 31  
 32 int EK(int s, int t)
 33 {
 34     int f, flow[LEN][LEN], a[LEN], p[LEN];
 35     queue<int> q;
 36     memset(flow, 0, sizeof flow);
 37     f = 0;
 38     while(1){
 39         memset(a, 0, sizeof a);
 40         a[s] = INF;
 41         q.push(s);
 42         while(!q.empty()){
 43             int u = q.front(); q.pop();
 44             for(int v=0; v<n; v++){
 45                 if(!a[v] && cap[u][v]>flow[u][v]){
 46                     p[v] = u;
 47                     q.push(v);
 48                     a[v] = min(a[u], cap[u][v]-flow[u][v]);
 49                 }
 50             }
 51         }
 52         if(a[t] == 0)break;
 53         for(int u=t; u!=s; u = p[u]){
 54             flow[p[u]][u]+=a[t];
 55             flow[u][p[u]]-=a[t];
 56         }
 57         f+=a[t];
 58     }
 59     return f;
 60 }
 61  
 62 int main()
 63 {
 64 //    freopen("in.txt", "r", stdin);
 65  
 66     int T;
 67     char str[51], sstr[51];
 68     scanf("%d", &T);
 69     while(T--){
 70         init();
 71         scanf("%d", &n);
 72         for(int i=1; i<=n ;i++){
 73             scanf("%s", str);
 74             int pos = ji(str);
 75             if(pos==-1){
 76                 strcpy(rec[tn], str);
 77                 numr[tn++] = 1;
 78             }
 79             else numr[pos] ++;
 80         }
 81         scanf("%d", &m);
 82         for(int i=1; i<=m; i++){
 83             scanf("%s%s", di[i], str);
 84             int pos = ji(str);
 85             if(pos == -1){
 86                 pos = tn;
 87                 strcpy(rec[tn], str);
 88                 numr[tn++] = 0;
 89             }
 90             cap[0][i] = 1;
 91             cap[i][m+1+pos] = 1;
 92         }
 93         scanf("%d", &k);
 94         for(int i=1; i<=k; i++){
 95             scanf("%s%s", str, sstr);
 96             if(ji(str)==-1){
 97                 strcpy(rec[tn], str);
 98                 numr[tn++] = 0;
 99             }
100             if(ji(sstr)==-1){
101                 strcpy(rec[tn], sstr);
102                 numr[tn++] = 0;
103             }
104 //            cout << str << " -> " << sstr << endl;
105             cap[m+1+ji(str)][m+1+ji(sstr)] = INF;
106         }
107         for(int i=0; i<tn; i++){
108             cap[m+1+i][m+tn+1] = numr[i];
109         }
110         n = m+tn+2;
111         int ans = EK(0, n-1);
112         cout << m-ans << endl;
113         if(T)cout << endl;
114     }
115     return 0;
116 }
View Code

 

转载于:https://www.cnblogs.com/shu-xiaohao/p/3476879.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值