Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 6728 | Accepted: 2751 |
Description
Input
Output
Sample Input
2 2 0 1 0 1 0 1 0 9 3 0 1 1 1 0 0 0 6 4 2 0 1 0 1 0 1 0 9 4 0 1 1 1 0 0 0 6 2
Sample Output
Yes No
Hint
A proper schedule for the first test case: date Sun Mon Tue Wed Thu Fri Sat week1 film1 film2 film1 film1 week2 film1 film2 film1 film1 week3 film1 film2 film1 film1 week4 film2 film2 film2
Source
x集是日期,y集是电影,将日期分配给有关联的电影;
最后判断是否能拍完只需看一下每一部电影是否被分配了足够的日期
将电影作为Y方点,每一天作为X方点(最多50周,每周7天,所以共设350个X方点),若第i个电影可以在第j天拍就连边(i, j)。最后判断匹配数是否等于所有电影要拍的天数和即可
代码有详细解释:
///多重匹配 /** 二分图多重匹配x集合是单流量 y集合可以多重匹配; */ #include<iostream> #include<algorithm> #include<string> #include <string.h> #include <stdio.h> #include<vector> using namespace std; const int M = 20+10; const int N = 350+10; int link[M][N],vlink[M],cap[M]; bool vis[M]; vector<int> g[N]; void init() { for(int i=0;i<N;i++) g[i].clear(); } int path(int s) { for(int it=0;it<g[s].size();it++) { int v=g[s][it]; if(!vis[v]) { vis[v]=true; if(vlink[v]<cap[v])///cap[v],表示y集合v点最多可以连几条边, ///y集合每个点固定流量时,只需要该这个点就行 { link[v][vlink[v]++]=s; return 1; } for(int j=0;j<vlink[v];j++) { if(path(link[v][j])) { link[v][j]=s; return 1; } } } } return 0; } bool max_match(int n,int m) { int ans=0; memset(vlink,0,sizeof(vlink)); for(int i=0;i<n;i++)///x集合,每个点只能用一次 { if(g[i].size()==0)///x集合不连续,并不是n天每天都有电影可以拍摄 continue; memset(vis,false,sizeof(vis)); if(path(i))///i点可以匹配出去 ans++; } ///ans值表示最大的匹配数 int num=0; for(int i=0;i<m;i++) { ///if(vlink[i]!=cap[i]) vlink 表示多重集合流量!!!这样也是可以的 num+=cap[i]; ///return false; } ///return true ; return ans==num; } int main() { int T; int n,m,a[10],w,maxw; scanf("%d",&T); while(T--) { scanf("%d",&m); maxw=0; init(); for(int i=0;i<m;i++) { for(int j=0;j<7;j++) scanf("%d",&a[j]); scanf("%d %d",&cap[i],&w); maxw=max(maxw,w); for(int j=0;j<7;j++) { if(a[j]) { for(int k=0;k<w;k++) g[k*7+j].push_back(i); } } } n=maxw*7; if(max_match(n,m)) puts("Yes"); else puts("No"); } return 0; }