题意:
给定 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 }