AC的故事大结局山寨版(下)(最大流)

Posted Q1143316492

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AC的故事大结局山寨版(下)(最大流)相关的知识,希望对你有一定的参考价值。

福建工程学院第十二届ACM程序设计大赛真题

AC的故事大结局山寨版(下)

TimeLimit:2000MS  MemoryLimit:128MB
64-bit integer IO format:%lld
已解决 | 点击收藏
Problem Description

小A算出幕后黑手的人员是如此之多,知道在我们华夏,手段通天者必然身居高位,仅仅靠他们的力量恐怕难以和他们对抗。

于是小A和小C找到了以前认识的检察官侯亮平,告诉侯亮平事情的始末后,他们立马通知赵东来安排了人手准备逮捕嫌疑人祁同伟(这么大的事居然没有事先向上级汇报就擅自行动)。

现在警厅里只有P<=100个警察,F<=100辆警车和C<=100把武器,每辆车和每把武器都有自己的特点,每个警察只会用其中的一些警车和武器。

每辆警车只坐一名警察(不知道为何要这么浪费资源,可能市局比较有钱),每位警察必须带上自己熟练的武器才能驾车出击。

为了打败幕后黑手祁同伟,小A合理安排后派出了最多的人手,相信你也一定知道派出了多少警察。最终成功逮捕了嫌疑人祁同伟。

从此小A和小C过上了幸福快乐的日子。可喜可贺,可喜可贺。

Input

先输入一个整数t(<=100)表示有多少组数据

每组输入3个整数P,F,C,(3个数都不超过100)分别表示警察人数,警车数量和武器数量。

接着第i行表示第i个警察的能力(共P行)。该行先输入两个整数x,y表示该警察会驾驶x辆汽车和y把武器,之后有x个整数表示警车的编号和y个整数表示武器的编号。

(警车编号:1~F,武器编号:1~C)

Output

每组输出一个整数,代表能带上武器驾车出击的警察最多有多少个

SampleInput
1
4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3
SampleOutput
3

思路:警察,武器,车都看作点,虚拟出源点汇点。保证源点到汇点必须经过一个警察,一个武器,一辆车。另外,警察要拆成两个点,为了避免警察被使用多次。所有关系作为流为1的边

正确的图:

错误的图:

 

 

 如果有一个人可以使用多个武器多辆车,那么该警察可能被使用多次。如下图,警察1就会贡献流量2。

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 const int MAXN = 1001;
  5 const int MAXM = 1e4 + 7;
  6 const int INF  = 0x7fffffff;
  7 typedef long long LL;
  8 
  9 int s, t, p, f, c;
 10 
 11 struct Edge {
 12     int to, w, next;
 13 } edge[MAXM * 4];
 14 
 15 int first[MAXN], cur[MAXN], sign, dist[MAXN];
 16 
 17 inline void init() {
 18     for(int i = 0; i < MAXN; i ++ ) {
 19         first[i] = -1;
 20     }
 21     sign = 0;
 22 }
 23 
 24 inline void add_edge(int u,int v,int w) {
 25     edge[sign].to = v, edge[sign].w = w;
 26     edge[sign].next = first[u], first[u] = sign++;
 27     edge[sign].to = u, edge[sign].w = 0;
 28     edge[sign].next = first[v], first[v] = sign++;
 29 }
 30 
 31 bool bfs(int s,int t) {
 32     memset(dist, -1, sizeof(dist));
 33     queue<int>que;
 34     que.push(s), dist[s] = 0;
 35     while(!que.empty()) {
 36         int now = que.front();
 37         que.pop();
 38         if(now == t) {
 39             return 1;
 40         }
 41         for(int i = first[now]; ~i; i = edge[i].next) {
 42             int to = edge[i].to, ww = edge[i].w;
 43             if(dist[to] == -1 && ww > 0) {
 44                 dist[to] = dist[now] + 1;
 45                 que.push(to);
 46             }
 47         }
 48     }
 49     return 0;
 50 }
 51 
 52 int dfs(int s, int t, int max_flow) {
 53     if(s == t) {
 54         return max_flow;
 55     }
 56     for(int &i = cur[s]; ~i; i = edge[i].next) {
 57         int to = edge[i].to, ww = edge[i].w;
 58         if(dist[to] == dist[s] + 1 && ww > 0) {
 59             int flow = dfs(to, t, min(max_flow, ww));
 60             if(flow > 0) {
 61                 edge[i].w -= flow;
 62                 edge[i ^ 1].w += flow;
 63                 return flow;
 64             }
 65         }
 66     }
 67     return 0;
 68 }
 69 
 70 int dinic(int s, int t) {
 71     int ans = 0;
 72     while(bfs(s, t)) {
 73         for(int i = 0; i < MAXN; i ++ ) {
 74             cur[i] = first[i];
 75         }
 76         ans += dfs(s, t, INF);
 77     }
 78     return ans;
 79 }
 80 
 81 template<class T>
 82 inline bool nextInt(T &n)
 83 {
 84     T x = 0, tmp = 1; char c = getchar();
 85     while((c < \'0\' || c > \'9\') && c != \'-\' && c != EOF) c = getchar();
 86     if(c == EOF) return false;
 87     if(c == \'-\') c = getchar(), tmp = -1;
 88     while(c >= \'0\' && c <= \'9\') x *= 10, x += (c - \'0\'),c = getchar();
 89     n = x*tmp;
 90     return true;
 91 }
 92 
 93 template<class T>
 94 inline void out(T n)
 95 {
 96     if(n < 0)
 97     {
 98         putchar(\'-\');
 99         n = -n;
100     }
101     int len = 0,data[20];
102     while(n)
103     {
104         data[len++] = n%10;
105         n /= 10;
106     }
107     if(!len) data[len++] = 0;
108     while(len--) putchar(data[len]+48);
109 }
110 
111 int main() {
112     int T;
113     nextInt(T);
114     while(T--) {
115         nextInt(p), nextInt(f), nextInt(c);
116         s = 0, t = 1000;
117         init();
118         for(int i = 1; i <= f; i++ ) { ///s->car
119             add_edge(s, i, 1);
120         }
121         for(int i = 1; i <= p; i++ ) { ///line
122             add_edge(i + 200, i + 400, 1);
123         }
124         for(int i = 1; i <= c; i++ ) { ///gun->t
125             add_edge(i + 600, t, 1);
126         }
127         for(int i = 1; i <= p; i++ ) {
128             int x, y, id;
129             nextInt(x), nextInt(y);
130             for(int j = 1; j <= x; j++ ) { ///car
131                 nextInt(id);
132                 add_edge(id, i + 200, 1);
133             }
134             for(int j = 1; j <= y; j++ ) { ///gun
135                 nextInt(id);
136                 add_edge(i + 400, id + 600, 1);
137             }
138         }
139         out(dinic(s, t)), putchar(\'\\n\');
140     }
141 
142     return 0;
143 }

 

以上是关于AC的故事大结局山寨版(下)(最大流)的主要内容,如果未能解决你的问题,请参考以下文章

普罗米修斯的故事,最后的结局

AC日记——模板最小费用最大流 P3381

解锁PK!全球首款屏下指纹手机对战iPhone X:结局很意外

多线程山寨云恢复使用

Codeforces 717G Underfail(最小费用最大流 + AC自动机)

故事可以有两种不一样的结局