题目大意:
班级有N名学生,运动会有M项不同的比赛,第i项比赛每个班需要派出m_i名选手参加,编号为i的学生最多同时参加给定的b_i项比赛中的任意a_i项比赛。
根据统计的结果,想知道能否有一个合适的安排,同时满足这些条件。
思路:
最大流求二分图多重匹配。
建立超级源点S、超级汇点T。
对于每一个学生i,连一条从S到i的容量为a_i的边。
对于每一项比赛i,连一条从i到T的容量为m_i的边。
对于每一个学生i和其所擅长的所有比赛j,连一条从i到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 }
时间: 2024-10-07 16:40:36