UVa 753 - A Plug for UNIX(最大流)

Posted Ctfes

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa 753 - A Plug for UNIX(最大流)相关的知识,希望对你有一定的参考价值。

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=694

 

题意:

有n个插座,m个设备和k(n,m,k≤100)种转换器,每种转换器都有无限多。已知每个插座的类型,每个设备的插头类型,
以及每种转换器的插座类型和插头类型。插头和插座类型都用不超过24个字母表示,插头只能插到类型名称相同的插座中。
例如,有4个插座,类型分别为A, B, C, D;有5个设备,插头类型分别为B, C, B, B, X;
还有3种转换器,分别是B->X,X->A和X->D。这里用B->X表示插座类型为B,插头类型为X,
因此一个插头类型为B的设备插上这种转换器之后就“变成”了一个插头类型为X的设备。
转换器可以级联使用,例如插头类型为A的设备依次接上A->B,B->C,C->D这3个转换器之后会“变成”插头类型为D的设备。
要求插的设备尽量多。问最少剩几个不匹配的设备。

 

分析:

首先要注意的是:k个转换器中涉及的插头类型不一定是接线板或者设备中出现过的插头类型。
在最坏情况下,100个设备,100个插座,100个转换器最多会出现400种插头。
当然,400种插头的情况肯定是无解的,但是如果编码不当,这样的情况可能会让程序出现下标越界等运行错误。
转换器有无限多,所以可以独立计算出每个设备i是否可以接上0个或多个转换器之后插到第j个插座上,
方法是建立有向图G,结点表示插头类型,边表示转换器,然后使用Floyd算法,
计算出任意一种插头类型a是否能转化为另一种插头类型b。
接下来构造网络:设设备i对应的插头类型编号为device[i],插座i对应的插头类型编号为recep[i],
则源点s到所有device[i]连一条弧,容量为1,然后所有recep[i]到汇点t连一条弧,容量为1,
对于所有设备i和插座j,如果device[i]可以转化为recep[j],则从device[i]连一条弧到recep[j],容量为1,
最后求s-t最大流,答案就是m减去最大流量。

 

代码:

  1 //Dinic版
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <string>
  5 #include <map>
  6 #include <vector>
  7 #include <queue>
  8 using namespace std;
  9 
 10 /// 结点下标从0开始,注意maxn
 11 struct Dinic {
 12     static const int maxn = 1e3 + 5;
 13     static const int INF = 0x3f3f3f3f;
 14     struct Edge {
 15         int from, to, cap, flow;
 16     };
 17 
 18     int n, m, s, t; // 结点数,边数(包括反向弧),源点编号和汇点编号
 19     vector<Edge> edges; // 边表。edges[e]和edges[e^1]互为反向弧
 20     vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
 21     bool vis[maxn]; // BFS使用
 22     int d[maxn]; // 从起点到i的距离
 23     int cur[maxn]; // 当前弧下标
 24 
 25     void init(int n) {
 26         this->n = n;
 27         edges.clear();
 28         for(int i = 0; i < n; i++) G[i].clear();
 29     }
 30     void AddEdge(int from, int to, int cap) {
 31         edges.push_back((Edge){from, to, cap, 0});
 32         edges.push_back((Edge){to, from, 0, 0});
 33         m = edges.size();
 34         G[from].push_back(m-2);
 35         G[to].push_back(m-1);
 36     }
 37     bool BFS() {
 38         memset(vis, 0, sizeof(vis));
 39         queue<int> Q;
 40         Q.push(s);
 41         vis[s] = 1;
 42         d[s] = 0;
 43         while(!Q.empty()) {
 44             int x = Q.front();  Q.pop();
 45             for(int i = 0; i < G[x].size(); i++) {
 46                 Edge& e = edges[G[x][i]];
 47                 if(!vis[e.to] && e.cap > e.flow) { // 只考虑残量网络中的弧
 48                     vis[e.to] = 1;
 49                     d[e.to] = d[x] + 1;
 50                     Q.push(e.to);
 51                 }
 52             }
 53         }
 54         return vis[t];
 55     }
 56     int DFS(int x, int a) {
 57         if(x == t || a == 0) return a;
 58         int flow = 0, f;
 59         for(int& i = cur[x]; i < G[x].size(); i++) { // 从上次考虑的弧
 60             Edge& e = edges[G[x][i]];
 61             if(d[x]+1 == d[e.to] && (f=DFS(e.to, min(a, e.cap-e.flow))) > 0) {
 62                 e.flow += f;
 63                 edges[G[x][i]^1].flow -= f;
 64                 flow += f;
 65                 a -= f;
 66                 if(a == 0) break;
 67             }
 68         }
 69         return flow;
 70     }
 71     int Maxflow(int s, int t) {
 72         this->s = s;  this->t = t;
 73         int flow = 0;
 74         while(BFS()) {
 75             memset(cur, 0, sizeof(cur));
 76             flow += DFS(s, INF);
 77         }
 78         return flow;
 79     }
 80     vector<int> Mincut() { // 在Maxflow之后调用
 81         vector<int> ans;
 82         for(int i = 0; i < edges.size(); i++) {
 83             Edge& e = edges[i];
 84             if(vis[e.from] && !vis[e.to] && e.cap > 0) ans.push_back(i);
 85         }
 86         return ans;
 87     }
 88 };
 89 
 90 const int UP = 100 + 5;
 91 int recep[UP], device[UP];
 92 bool can[UP*4][UP*4];
 93 map<string,int> ids;
 94 Dinic dc;
 95 
 96 int id(string s) {
 97     if(ids.count(s)) return ids[s];
 98     int i = ids.size();
 99     return ids[s] = i;
100 }
101 
102 void floyd() {
103     int n = ids.size();
104     for(int i = 0; i < n; i++) can[i][i] = true;
105     for(int k = 0; k < n; k++) {
106         for(int i = 0; i < n; i++) {
107             for(int j = 0; j < n; j++) {
108                 can[i][j] |= can[i][k] && can[k][j];
109             }
110         }
111     }
112 }
113 
114 int main() {
115     int T, n, m, k;
116     char s[24+5], s2[24+5];
117     scanf("%d", &T);
118     while(T--) {
119         ids.clear();
120         memset(can, false, sizeof(can));
121         scanf("%d", &n);
122         for(int i = 0; i < n; i++) {
123             scanf("%s", s);
124             recep[i] = id(s);
125         }
126         scanf("%d", &m);
127         for(int i = 0; i < m; i++) {
128             scanf("%s%s", s2, s);
129             device[i] = id(s);
130         }
131         scanf("%d", &k);
132         for(int i = 0; i < k; i++) {
133             scanf("%s%s", s, s2);
134             can[id(s)][id(s2)] = true;
135         }
136 
137         floyd();
138         int V = ids.size();
139         dc.init(V+2);
140         for(int i = 0; i < m; i++) dc.AddEdge(V, device[i], 1);
141         for(int i = 0; i < n; i++) dc.AddEdge(recep[i], V+1, 1);
142         for(int i = 0; i < m; i++) {
143             for(int t = 0; t < n; t++) {
144                 if(!can[device[i]][recep[t]]) continue;
145                 dc.AddEdge(device[i], recep[t], 1);
146             }
147         }
148         printf("%d
", m - dc.Maxflow(V, V+1));
149         if(T) printf("
");
150     }
151     return 0;
152 }

 

  1 //ISAP版
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <string>
  5 #include <map>
  6 #include <vector>
  7 #include <queue>
  8 using namespace std;
  9 
 10 /// 结点下标从0开始,注意maxn
 11 struct ISAP {
 12     static const int maxn = 1e3 + 5;
 13     static const int INF = 0x3f3f3f3f;
 14     struct Edge {
 15         int from, to, cap, flow;
 16     };
 17 
 18     int n, m, s, t; // 结点数,边数(包括反向弧),源点编号和汇点编号
 19     vector<Edge> edges; // 边表。edges[e]和edges[e^1]互为反向弧
 20     vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
 21     bool vis[maxn]; // BFS使用
 22     int d[maxn]; // 从起点到i的距离
 23     int cur[maxn]; // 当前弧下标
 24     int p[maxn]; // 可增广路上的上一条弧
 25     int num[maxn]; // 距离标号计数
 26 
 27     void init(int n) {
 28         this->n = n;
 29         edges.clear();
 30         for(int i = 0; i < n; i++) G[i].clear();
 31     }
 32     void AddEdge(int from, int to, int cap) {
 33         edges.push_back((Edge){from, to, cap, 0});
 34         edges.push_back((Edge){to, from, 0, 0});
 35         m = edges.size();
 36         G[from].push_back(m-2);
 37         G[to].push_back(m-1);
 38     }
 39     bool BFS() {
 40         memset(vis, 0, sizeof(vis));
 41         queue<int> Q;
 42         Q.push(t);
 43         vis[t] = 1;
 44         d[t] = 0;
 45         while(!Q.empty()) {
 46             int x = Q.front();  Q.pop();
 47             for(int i = 0; i < G[x].size(); i++) {
 48                 Edge& e = edges[G[x][i]^1];
 49                 if(!vis[e.from] && e.cap > e.flow) {
 50                     vis[e.from] = 1;
 51                     d[e.from] = d[x] + 1;
 52                     Q.push(e.from);
 53                 }
 54             }
 55         }
 56         return vis[s];
 57     }
 58     int Augment() {
 59         int x = t, a = INF;
 60         while(x != s) {
 61             Edge& e = edges[p[x]];
 62             a = min(a, e.cap-e.flow);
 63             x = edges[p[x]].from;
 64         }
 65         x = t;
 66         while(x != s) {
 67             edges[p[x]].flow += a;
 68             edges[p[x]^1].flow -= a;
 69             x = edges[p[x]].from;
 70         }
 71         return a;
 72     }
 73     int Maxflow(int s, int t) {
 74         this->s = s;  this->t = t;
 75         int flow = 0;
 76         BFS();
 77         memset(num, 0, sizeof(num));
 78         for(int i = 0; i < n; i++) num[d[i]]++;
 79         int x = s;
 80         memset(cur, 0, sizeof(cur));
 81         while(d[s] < n) {
 82             if(x == t) {
 83                 flow += Augment();
 84                 x = s;
 85             }
 86             int ok = 0;
 87             for(int i = cur[x]; i < G[x].size(); i++) {
 88                 Edge& e = edges[G[x][i]];
 89                 if(e.cap > e.flow && d[x] == d[e.to] + 1) { // Advance
 90                     ok = 1;
 91                     p[e.to] = G[x][i];
 92                     cur[x] = i; // 注意
 93                     x = e.to;
 94                     break;
 95                 }
 96             }
 97             if(!ok) { // Retreat
 98                 int m = n-1; // 初值注意
 99                 for(int i = 0; i < G[x].size(); i++) {
100                     Edge& e = edges[G[x][i]];
101                     if(e.cap > e.flow) m = min(m, d[e.to]);
102                 }
103                 if(--num[d[x]] == 0) break; // gap优化
104                 num[d[x] = m+1]++;
105                 cur[x] = 0; // 注意
106                 if(x != s) x = edges[p[x]].from;
107             }
108         }
109         return flow;
110     }
111     vector<int> Mincut() { // 在Maxflow之后调用
112         BFS();
113         vector<int> ans;
114         for(int i = 0; i < edges.size(); i++) {
115             Edge& e = edges[i];
116             if(!vis[e.from] && vis[e.to] && e.cap > 0) ans.push_back(i);
117         }
118         return ans;
119     }
120 };
121 
122 const int UP = 100 + 5;
123 int recep[UP], device[UP];
124 bool can[UP*4][UP*4];
125 map<string,int> ids;
126 ISAP is;
127 
128 int id(string s) {
129     if(ids.count(s)) return ids[s];
130     int i = ids.size();
131     return ids[s] = i;
132 }
133 
134 void floyd() {
135     int n = ids.size();
136     for(int i = 0; i < n; i++) can[i][i] = true;
137     for(int k = 0; k < n; k++) {
138         for(int i = 0; i < n; i++) {
139             for(int j = 0; j < n; j++) {
140                 can[i][j] |= can[i][k] && can[k][j];
141             }
142         }
143     }
144 }
145 
146 int main() {
147     int T, n, m, k;
148     char s[24+5], s2[24+5];
149     scanf("%d", &T);
150     while(T--) {
151         ids.clear();
152         memset(can, false, sizeof(can));
153         scanf("%d", &n);
154         for(int i = 0; i < n; i++) {
155             scanf("%s", s);
156             recep[i] = id(s);
157         }
158         scanf("%d", &m);
159         for(int i = 0; i < m; i++) {
160             scanf("%s%s", s2, s);
161             device[i] = id(s);
162         }
163         scanf("%d", &k);
164         for(int i = 0; i < k; i++) {
165             scanf("%s%s", s, s2);
166             can[id(s)][id(s2)] = true;
167         }
168 
169         floyd();
170         int V = ids.size();
171         is.init(V+2);
172         for(int i = 0; i < m; i++) is.AddEdge(V, device[i], 1);
173         for(int i = 0; i < n; i++) is.AddEdge(recep[i], V+1, 1);
174         for(int i = 0; i < m; i++) {
175             for(int t = 0; t < n; t++) {
176                 if(!can[device[i]][recep[t]]) continue;
177                 is.AddEdge(device[i], recep[t], 1);
178             }
179         }
180         printf("%d
", m - is.Maxflow(V, V+1));
181         if(T) printf("
");
182     }
183     return 0;
184 }

 
















以上是关于UVa 753 - A Plug for UNIX(最大流)的主要内容,如果未能解决你的问题,请参考以下文章

UVA753:A Plug for UNIX

UVa 753 - A Plug for UNIX(最大流)

uva753 A Plug for UNIX

题解 UVA753 UNIX插头 A Plug for UNIX

A Plug for UNIX UVA - 753(网络流)

uva 753A Plug for UNIX(图论--最大流 Dinic)