题目链接:
http://hihocoder.com/problemset/problem/1393
分析:
很简单的一道匹配题目
用流可以解决一切匹配(某大牛说的,,)
所以舍弃KM转到流的怀抱吧
将容量视为人数
人和比赛之间的容量置为1
比赛和汇点之间的容量置为这个比赛需要的人数
源点和人之间自然是人能参加比赛的个数(当作TA使用了分身术吧)
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
#define maxn 555
int N,M;
int S,T;
int sum;
const int INF = 1e9;
struct Edge{
int from,to,cap,flow;
Edge(int f,int t,int c,int ff)
:from(f),to(t),cap(c),flow(ff) {};
};
vector<Edge> edges;
vector<int> G[maxn];
int iter[maxn] ,level[maxn];
int vis[maxn];
void add_Edge(int from,int to,int cap)
{
edges.push_back( Edge(from,to,cap,0) );
edges.push_back( Edge(to,from,0,0) );
int sz = edges.size();
G[from].push_back(sz-2);
G[to].push_back(sz-1);
}
bool BFS( )
{
// printf("!\n");
memset(vis,false,sizeof(vis));
level[S] = 0;
vis[S] = 1;
queue<int>Q;
Q.push(S);
while(!Q.empty())
{
int u = Q.front();
Q.pop();
for(int i = 0 ; i < G[u].size() ; ++i)
{
Edge& e = edges[G[u][i]];
if(!vis[e.to]&&e.cap > e.flow)
{
vis[e.to] = 1;
level[e.to] = level[u] + 1;
Q.push(e.to);
}
}
}
return vis[T];
}
int DFS(int u ,int a)
{
// printf("@\n");
if(u == T || a == 0)
return a;
int f , flow = 0;
for(int& i = iter[u]; i < (int)G[u].size(); ++i)// ?
{
Edge& e = edges[G[u][i]];
if(level[e.to] == level[u] + 1 && (f = DFS(e.to , min(a,e.cap - e.flow))) > 0 )
{
e.flow += f;
edges[G[u][i]^1].flow -= f;
return f;
}
}
return flow;
}
int Dinic( )
{
int res = 0 ;
while(BFS())
{
memset(iter,0,sizeof(iter));
res += DFS(S,INF);
}
return res;
}
void init()
{
S = 0 , T = N + M + 1;
for(int i = 0 ; i <= T ; ++i)
G[i].clear();
edges.clear();
}
int main()
{
int t;cin>>t;
while(t--)
{
cin >> N >> M;
init();
sum = 0;
for(int i = 1 ; i <= M ; ++i)
{
int cap;
scanf("%d",&cap);
sum+=cap;
add_Edge(N+i,T,cap);
}
for(int i = 1 ; i <= N ; ++i)
{
int a,b;
scanf("%d%d",&a,&b);
add_Edge(0,i,a);
for(int j=0;j<b;j++)
{
int to;
scanf("%d",&to);
add_Edge(i,N+to,1);
}
}
if( sum == Dinic() )printf("Yes\n");
else printf("No\n");
}
}