構圖很重要。。。
每部電影作為一個源點,然後把每個星期的每一天看成一個點,每個點只可以貢獻一個工作日,即出邊(到匯點)的容量只能是1,而入邊的容量也為1,只要某部電影可以在該天工作,就可能選擇該天,即該部電影對應的點到該個工作日對應的點之間連一條線,最後,添加一個超級源點,它到每部電影對於的點之間的容量為該部電影需要的工作日(不能為無窮大)
一開始把工作日與電影的關係對應反了,讓工作日去找電影,這樣節點個數就有50×20×7,太多了,實際上,電影在每一個工作日上都重複一次,何不讓電影去找工作日呢?這樣每個電影節點就只會出現一次了
代碼:
#include<iostream><br />using namespace std;<br />#define inf 999999<br />int f[375][375],cap[375][375];<br />int pre[375],rc[375],q[375],w[51][8];<br />int n,m,ans;<br />bool bfs()<br />{<br />int i,j,head=0,tail=1;<br />memset(rc,0,sizeof(rc));<br />pre[0]=-1;<br />rc[0]=9999999;<br />q[tail]=0;<br />while(head<tail)<br />{<br />i=q[++head];<br />for(j=1;j<=n+m*7+1;j++)<br />{<br />if(cap[i][j]>f[i][j]&&!rc[j])<br />{<br />rc[j]=rc[i];<br />if(cap[i][j]-f[i][j]<rc[j])<br />rc[j]=cap[i][j]-f[i][j];<br />pre[j]=i;<br />q[++tail]=j;<br />if(j==n+m*7+1)<br />return true;<br />}<br />}<br />}<br />return false;<br />}<br />void update()<br />{<br />for(int i=n+m*7+1;i!=0;i=pre[i])<br />{<br />f[pre[i]][i]+=rc[n+m*7+1];<br />f[i][pre[i]]=-f[pre[i]][i];<br />}<br />ans+=rc[n+m*7+1];<br />}<br />void EK()<br />{<br />while(bfs())<br />update();<br />}<br />int main()<br />{<br />int i,j,k,deadline[51],test,sum,day;<br />cin>>test;<br />while(test--)<br />{<br />scanf("%d",&n);<br />memset(f,0,sizeof(f));<br />memset(cap,0,sizeof(cap));<br />m=-1;<br />sum=0;<br />for(i=1;i<=n;i++)<br />{<br />for(j=1;j<=7;j++)<br />scanf("%d",&w[i][j]);<br />scanf("%d%d",&day,&deadline[i]);<br />cap[0][i]=day;<br />if(deadline[i]>m)<br />m=deadline[i];<br />sum+=day;<br />}<br />for(i=1;i<=n;i++)<br />for(j=1;j<=deadline[i];j++)<br />{<br />for(k=1;k<=7;k++)<br />{<br />if(w[i][k])<br />{<br />cap[i][n+(j-1)*7+k]+=1;<br />cap[n+(j-1)*7+k][n+m*7+1]=1;<br />}<br />}<br />}<br />ans=0;<br />EK();<br />if(ans==sum)<br />printf("Yes/n");<br />else<br />printf("No/n");<br />}<br />return 0;<br />}