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

时间:2022-11-15 19:28:34

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

这题的话有坑点,刚开始写的时候,是直接如下建图的

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

这样建图就会出现一种情况,一个人会被重复使用,

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

所以这时候就应该这一个点分成两个点,用流量为1的边连接,如果这个人使用了,流量减为0,这样就不会被重复使用

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

 #include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
struct Dinic
{
static const int MAXN = + ; ///改网络流的点
static const int MAXM = MAXN * MAXN; ///改网络流的边
static const int INF = 0x3f3f3f3f; ///看情况改 int n, m, s, t;
int first[MAXN], cur[MAXN], dist[MAXN], sign; struct Node
{
int to, flow, next;
} edge[MAXM * ]; inline void init(int start, int vertex, int ss, int tt)
{
n = vertex, s = ss, t = tt;
for(int i = start; i <= n; i++ )
{
first[i] = -;
}
sign = ;
}
inline void add_edge(int u, int v, int flow)
{
edge[sign].to = v, edge[sign].flow = flow, edge[sign].next = first[u];
first[u] = sign++;
edge[sign].to = u, edge[sign].flow = , edge[sign].next = first[v];
first[v] = sign++;
} inline int dinic()
{
int max_flow = ;
while(bfs(s, t))
{
for(int i = ; i <= n; i++ )
{
cur[i] = first[i];
}
max_flow += dfs(s, INF);
}
return max_flow;
}
bool bfs(int s, int t)
{
memset(dist, -, sizeof(dist));
queue<int>que;
que.push(s), dist[s] = ;
while(!que.empty())
{
int now = que.front();
que.pop();
if(now == t)
{
return ;
}
for(int i = first[now]; ~i; i = edge[i].next)
{
int to = edge[i].to, flow = edge[i].flow;
if(dist[to] == - && flow > )
{
dist[to] = dist[now] + ;
que.push(to);
}
}
}
return ;
}
int dfs(int now, int max_flow)
{
if(now == t)
{
return max_flow;
}
int ans = , next_flow = ;
for(int &i = cur[now]; ~i; i = edge[i].next)
{
int to = edge[i].to, flow = edge[i].flow;
if(dist[to] == dist[now] + && flow > )
{
next_flow = dfs(to, min(max_flow - ans, flow));
ans += next_flow;
edge[i].flow -= next_flow;
edge[i ^ ].flow += next_flow;
if(ans == max_flow)
{
return max_flow;
}
}
}
if(ans == )
{
return dist[now] = ;
}
return ans;
} } dinic; /**
.init(点编号起点, 点编号终点, 源点, 汇点)
.add_edge(u, v, w) 加边
.dinic() 输出最大流
*/ int a[],b[];
int main()
{
int t,p,f,c;
scanf("%d",&t);
while(t--)
{
int s=,t=;
dinic.init(s,t,s,t); scanf("%d%d%d",&p,&f,&c);
for(int i=; i<=f; i++) ///s->车
dinic.add_edge(s,i,);
for(int i=;i<=p;i++)
dinic.add_edge(i+,i+,);
for(int i=; i<=c; i++)
dinic.add_edge(i+,t,); ///枪->t
for(int i=; i<=p; i++)
{
int x,y;
scanf("%d%d",&x,&y);
for(int j=; j<=x; j++) ///车
{
int z;
scanf("%d",&z);
dinic.add_edge(z,i+,);
}
for(int j=; j<=y; j++)
{
int z;
scanf("%d",&z);
dinic.add_edge(i+,z+,);
}
}
printf("%d\n",dinic.dinic());
}
return ;
}