POJ

原题链接

题意:

给定 N 个不同类型插座,每个插座只能插一个相对应的设备 ;

现有 M 个人,给出每个人名字和设备的插头类型,然后给定 K 种转换器,每种转换器的数量都是无限的,每种转化器描述为: 插座类型,插头类型;

现在问至少有多少个人的设备无法插入。

思路:

一个典型的最大流问题,设定超级源点 S , 超级汇点 T ,将每种插座与 S 相连,流量为1;将所有人的插头类型统计一下,并记录数量,然后将其与汇点相连,流量为每种插头的数量;

记录所有的转换器,用 Floyd 算出 每种插头最终可以转化插头并将这个插头与对应的插座相连(如果都存在的话),最后跑一遍最大流,就是能够使用插座的人数,剩下的即为答案;

  1 /*
  2 * @Author: windystreet
  3 * @Date:   2018-07-31 20:57:04
  4 * @Last Modified by:   windystreet
  5 * @Last Modified time: 2018-08-01 11:57:21
  6 */
  7 
  8 #include <stdio.h>
  9 #include <algorithm>
 10 #include <string.h>
 11 #include <vector>
 12 #include <iostream>
 13 #include <map>
 14 #include <string>
 15 #include <queue>
 16 #include <utility>
 17 
 18 using namespace std;
 19 
 20 #define X first
 21 #define Y second
 22 #define eps  1e-2
 23 #define gcd __gcd
 24 #define pb push_back
 25 #define PI acos(-1.0)
 26 #define lowbit(x) (x)&(-x)
 27 #define bug printf("!!!!!
");
 28 #define mem(x,y) memset(x,y,sizeof(x))
 29 
 30 
 31 typedef long long LL;
 32 typedef long double LD;
 33 typedef pair<int,int> pii;
 34 typedef unsigned long long uLL;
 35 
 36 const int maxn = 1000+2;
 37 const int INF  = 1<<30;
 38 const int mod  = 1e9+7;
 39 
 40 struct Edge{
 41      int from,to,cap,flow;
 42 };
 43 
 44 struct Dinic
 45 {
 46     int n,m,s,t;
 47     vector<Edge>edge;
 48     vector<int>G[maxn];
 49     bool vis[maxn];
 50     int d[maxn];
 51     int cur[maxn];
 52     void init(int n){
 53         this->n = n;
 54         for(int i=0;i<=n;i++)G[i].clear(),edge.clear();
 55     }
 56     void addedge(int from,int to,int cap){
 57         edge.pb((Edge){from,to,cap,0});
 58         edge.pb((Edge){to,from,0,0});
 59         m = edge.size();
 60         G[from].pb(m-2);
 61         G[to].pb(m-1);
 62     }
 63     bool bfs(){
 64         mem(vis,0);
 65         queue<int>Q;
 66         Q.push(s);
 67         d[s] = 0;
 68         vis[s] = 1;
 69         while(!Q.empty()){
 70             int x = Q.front(); Q.pop();
 71             int sz = G[x].size();
 72             for(int i=0;i<sz;++i){
 73                 Edge &e = edge[G[x][i]];
 74                 if(!vis[e.to] && e.cap>e.flow){
 75                     vis[e.to] = 1 ;
 76                     d[e.to] = d[x] + 1;
 77                     Q.push(e.to); 
 78                 }
 79             }
 80         }
 81         return vis[t];
 82     }
 83     int dfs(int x,int a){
 84         if(x == t || a == 0)return a;
 85         int flow = 0,f;
 86         int sz = G[x].size();
 87         for(int &i = cur[x];i<sz;i++){
 88             Edge &e = edge[G[x][i]];
 89             if(d[x] + 1 == d[e.to] && (f = dfs(e.to,min(a,e.cap - e.flow)))>0){
 90                 e.flow += f;
 91                 edge[G[x][i]^1].flow -=f;
 92                 flow += f;
 93                 a -= f;
 94                 if(a==0)break;
 95             }
 96         }
 97         if(!flow) d[x] = -2;
 98         return flow;
 99     }
100     int maxflow(int s,int t){
101         this->s = s; this -> t = t;
102         int flow = 0;
103         while(bfs()){
104             mem(cur,0);
105             flow += dfs(s,INF);
106         }
107         return flow;
108     }
109 };
110 int vis1[410];
111 int vis2[420];
112 int dp[400][400];
113 int n,m,c,s = 0 ,t = 808;
114 map<string,int>id;
115 string s1,s2,name;
116 Dinic dinic;
117 void solve(){
118     id.clear();
119     int cnt = 1;
120       mem(dp,0x3f3f3f3f);
121     cin>>n;
122     for(int i=1;i<=n;i++){
123         cin>>s1;
124         id[s1] = cnt;                     // 记录每一个插座的id
125         dinic.addedge(s,cnt,1);
126         vis1[cnt++] = 1;                // 标记该类型的插座已经存在
127     }
128     cin>>m;
129     map<int,int>mp;
130     mp.clear();
131     for(int i=1;i<=m;i++){
132         cin>>name>>s1;
133         if(!id[s1]){
134             id[s1]=cnt;
135             cnt++;
136         }
137         mp[id[s1]]++;                    // 记录每种插头出现的次数
138     }
139     map<int,int>::iterator it = mp.begin();
140     for(;it!=mp.end();it++){
141         dinic.addedge(it->X+400,t,it->Y);// 插头与汇点相连,流量为插头数量
142         vis2[it->X] = 1;                // 标记该类型的插头已经存在
143     }
144     cin>>c;
145     for(int i=1;i<=c;i++){
146         cin>>s1>>s2;
147         if(!id[s1]) id[s1] = cnt++;
148         if(!id[s2]) id[s2] = cnt++;
149         dp[id[s1]][id[s2]] = 1;
150     }
151     for(int k = 1 ;k <= cnt;k++){        // floyd处理可转化的结果
152         for(int i = 1;i <= cnt;i++ ){
153             for(int j = 1;j<=cnt;j++){
154                 if(dp[i][k]==1&&dp[k][j]==1){
155                     dp[i][j] =  1;
156                 }
157             }
158         }
159     }         
160     for(int i=1;i<=cnt;i++){
161         if(vis1[i]&&vis2[i]){
162             dinic.addedge(i,i+400,1);   // 如果该类型的插座和插头都存在,就相连
163         }
164     }
165     for(int i=1;i<=cnt;i++){
166         for(int j=1;j<=cnt;j++){
167             if(dp[i][j]==1&&vis1[j]&&vis2[i]){
168                 dinic.addedge(j,i+400,1); // 转化之后的结果
169             }
170         }
171     }
172     int ans = dinic.maxflow(s,t);
173     printf("%d
",m-ans );
174     return;
175 }
176 
177 int main()
178 {
179 //    freopen("in.txt","r",stdin);
180 //    freopen("out.txt","w",stdout);
181     ios::sync_with_stdio(false);
182     int t = 1;
183     //scanf("%d",&t);
184     while(t--){
185     //    printf("Case %d: ",cas++);
186         solve();
187     }
188     return 0;
189 }
原文地址:https://www.cnblogs.com/windystreet/p/9402515.html