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

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的边连接,如果这个人使用了,流量减为0,这样就不会被重复使用

 

然后其他的就是标准的最小费用最大流解法了,用一个源点连接所有起始点,用一个汇点连接所有结束点,流量cap=1,cost=0,

  1 #include<stdio.h>
  2 #include<algorithm>
  3 #include<string.h>
  4 #include<queue>
  5 using namespace std;
  6 struct Dinic
  7 {
  8     static const int MAXN = 1025 + 7; ///改网络流的点
  9     static const int MAXM = MAXN * MAXN; ///改网络流的边
 10     static const int INF = 0x3f3f3f3f; ///看情况改
 11 
 12     int n, m, s, t;
 13     int first[MAXN], cur[MAXN], dist[MAXN], sign;
 14 
 15     struct Node
 16     {
 17         int to, flow, next;
 18     } edge[MAXM * 4];
 19 
 20     inline void init(int start, int vertex, int ss, int tt)
 21     {
 22         n = vertex, s = ss, t = tt;
 23         for(int i = start; i <= n; i++ )
 24         {
 25             first[i] = -1;
 26         }
 27         sign = 0;
 28     }
 29     inline void add_edge(int u, int v, int flow)
 30     {
 31         edge[sign].to = v, edge[sign].flow = flow, edge[sign].next = first[u];
 32         first[u] = sign++;
 33         edge[sign].to = u, edge[sign].flow = 0, edge[sign].next = first[v];
 34         first[v] = sign++;
 35     }
 36 
 37     inline int dinic()
 38     {
 39         int max_flow = 0;
 40         while(bfs(s, t))
 41         {
 42             for(int i = 0; i <= n; i++ )
 43             {
 44                 cur[i] = first[i];
 45             }
 46             max_flow += dfs(s, INF);
 47         }
 48         return max_flow;
 49     }
 50     bool bfs(int s, int t)
 51     {
 52         memset(dist, -1, sizeof(dist));
 53         queue<int>que;
 54         que.push(s), dist[s] = 0;
 55         while(!que.empty())
 56         {
 57             int now = que.front();
 58             que.pop();
 59             if(now == t)
 60             {
 61                 return 1;
 62             }
 63             for(int i = first[now]; ~i; i = edge[i].next)
 64             {
 65                 int to = edge[i].to, flow = edge[i].flow;
 66                 if(dist[to] == -1 && flow > 0)
 67                 {
 68                     dist[to] = dist[now] + 1;
 69                     que.push(to);
 70                 }
 71             }
 72         }
 73         return 0;
 74     }
 75     int dfs(int now, int max_flow)
 76     {
 77         if(now == t)
 78         {
 79             return max_flow;
 80         }
 81         int ans = 0, next_flow = 0;
 82         for(int &i = cur[now]; ~i; i = edge[i].next)
 83         {
 84             int to = edge[i].to, flow = edge[i].flow;
 85             if(dist[to] == dist[now] + 1 && flow > 0)
 86             {
 87                 next_flow = dfs(to, min(max_flow - ans, flow));
 88                 ans += next_flow;
 89                 edge[i].flow -= next_flow;
 90                 edge[i ^ 1].flow += next_flow;
 91                 if(ans == max_flow)
 92                 {
 93                     return max_flow;
 94                 }
 95             }
 96         }
 97         if(ans == 0)
 98         {
 99             return dist[now] = 0;
100         }
101         return ans;
102     }
103 
104 } dinic;
105 
106 /**
107 .init(点编号起点, 点编号终点, 源点, 汇点)
108 .add_edge(u, v, w) 加边
109 .dinic() 输出最大流
110 */
111 
112 int a[1200],b[2000];
113 int main()
114 {
115     int t,p,f,c;
116     scanf("%d",&t);
117     while(t--)
118     {
119         int s=0,t=1000;
120         dinic.init(s,t,s,t);
121 
122         scanf("%d%d%d",&p,&f,&c);
123         for(int i=1; i<=f; i++) ///s->车
124             dinic.add_edge(s,i,1);
125             for(int i=1;i<=p;i++)
126                 dinic.add_edge(i+200,i+400,1);
127         for(int i=1; i<=c; i++)
128             dinic.add_edge(i+600,t,1); ///枪->t
129         for(int i=1; i<=p; i++)
130         {
131             int x,y;
132             scanf("%d%d",&x,&y);
133             for(int j=1; j<=x; j++) ///
134             {
135                 int z;
136                 scanf("%d",&z);
137                 dinic.add_edge(z,i+200,1);
138             }
139             for(int j=1; j<=y; j++)
140             {
141                  int z;
142                 scanf("%d",&z);
143                 dinic.add_edge(i+400,z+600,1);
144             }
145         }
146         printf("%d\n",dinic.dinic());
147     }
148     return 0;
149 }
View Code

 

 

 
  

转载于:https://www.cnblogs.com/yuanlinghao/p/9432982.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值