题目大意:

班级有$N$名学生,运动会有$M$项不同的比赛,第$i$项比赛每个班需要派出$m_i$名选手参加,编号为i的学生最多同时参加给定的$b_i$项比赛中的任意$a_i$项比赛。
根据统计的结果,想知道能否有一个合适的安排,同时满足这些条件。

思路:

最大流求二分图多重匹配。
建立超级源点$S$、超级汇点$T$。
对于每一个学生$s_i$,连一条从$S$到$s_i$的容量为$a_i$的边。
对于每一项比赛$c_i$,连一条从$c_i$到$T$的容量为$m_i$的边。
对于每一个学生$s_i$和其所擅长的所有比赛$c_j$,连一条从$s_i$到$c_j$的容量为1的边。
计算最大流$F$,当$F=Σm_i$时,条件满足。

 #include<cstdio>
#include<cctype>
#include<vector>
#include<queue>
#include<cstring>
inline int getint() {
char ch;
while(!isdigit(ch=getchar()));
int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
struct Edge {
int from,to,remain;
};
const int E=,V=,inf=0x7fffffff;
Edge e[E<<];
int sz;
std::vector<int> g[V];
inline void add_edge(const int u,const int v,const int w) {
e[sz]=(Edge){u,v,w};
g[u].push_back(sz);
sz++;
}
int s,t;
void reset() {
sz=;
for(int i=;i<V;i++) g[i].clear();
}
int a[V],p[V];
inline int Augment() {
std::queue<int> q;
q.push(s);
memset(a,,sizeof a);
a[s]=inf;
while(!q.empty()&&!a[t]) {
int x=q.front();
q.pop();
for(unsigned i=;i<g[x].size();i++) {
Edge &y=e[g[x][i]];
if(!a[y.to]&&y.remain) {
p[y.to]=g[x][i];
a[y.to]=std::min(a[x],y.remain);
q.push(y.to);
}
}
}
return a[t];
}
inline int EdmondsKarp() {
int maxflow=;
while(int flow=Augment()) {
for(int i=t;i!=s;i=e[p[i]].from) {
e[p[i]].remain-=flow;
e[p[i]^].remain+=flow;
}
maxflow+=flow;
}
return maxflow;
}
int main() {
for(int T=getint();T;T--) {
reset();
int n=getint(),m=getint();
s=,t=n+m+;
int sum=;
for(int i=;i<=m;i++) {
int w=getint();
sum+=w;
add_edge(n+i,t,w);
add_edge(t,n+i,);
}
for(int i=;i<=n;i++) {
int a=getint(),b=getint();
add_edge(s,i,a);
add_edge(i,s,);
while(b--) {
int v=getint();
add_edge(i,n+v,);
add_edge(n+v,i,);
}
}
puts(EdmondsKarp()==sum?"Yes":"No");
}
return ;
}
05-08 08:23