[HihoCoder1393]网络流三·二分图多重匹配
题目大意:
班级有$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$时,条件满足。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 #include<queue> 5 #include<cstring> 6 inline int getint() { 7 char ch; 8 while(!isdigit(ch=getchar())); 9 int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 struct Edge { 14 int from,to,remain; 15 }; 16 const int E=10200,V=202,inf=0x7fffffff; 17 Edge e[E<<1]; 18 int sz; 19 std::vector<int> g[V]; 20 inline void add_edge(const int u,const int v,const int w) { 21 e[sz]=(Edge){u,v,w}; 22 g[u].push_back(sz); 23 sz++; 24 } 25 int s,t; 26 void reset() { 27 sz=0; 28 for(int i=0;i<V;i++) g[i].clear(); 29 } 30 int a[V],p[V]; 31 inline int Augment() { 32 std::queue<int> q; 33 q.push(s); 34 memset(a,0,sizeof a); 35 a[s]=inf; 36 while(!q.empty()&&!a[t]) { 37 int x=q.front(); 38 q.pop(); 39 for(unsigned i=0;i<g[x].size();i++) { 40 Edge &y=e[g[x][i]]; 41 if(!a[y.to]&&y.remain) { 42 p[y.to]=g[x][i]; 43 a[y.to]=std::min(a[x],y.remain); 44 q.push(y.to); 45 } 46 } 47 } 48 return a[t]; 49 } 50 inline int EdmondsKarp() { 51 int maxflow=0; 52 while(int flow=Augment()) { 53 for(int i=t;i!=s;i=e[p[i]].from) { 54 e[p[i]].remain-=flow; 55 e[p[i]^1].remain+=flow; 56 } 57 maxflow+=flow; 58 } 59 return maxflow; 60 } 61 int main() { 62 for(int T=getint();T;T--) { 63 reset(); 64 int n=getint(),m=getint(); 65 s=0,t=n+m+1; 66 int sum=0; 67 for(int i=1;i<=m;i++) { 68 int w=getint(); 69 sum+=w; 70 add_edge(n+i,t,w); 71 add_edge(t,n+i,0); 72 } 73 for(int i=1;i<=n;i++) { 74 int a=getint(),b=getint(); 75 add_edge(s,i,a); 76 add_edge(i,s,0); 77 while(b--) { 78 int v=getint(); 79 add_edge(i,n+v,1); 80 add_edge(n+v,i,0); 81 } 82 } 83 puts(EdmondsKarp()==sum?"Yes":"No"); 84 } 85 return 0; 86 }