從源到每個人連一條容量爲 \(1\) 的邊。
從每個導師到匯連一條容量爲導師戰隊人數的邊。
第一問咱們依次枚舉每個學員,而後再依次與第 \(1\)至 \(m\) 志願的老師連邊,若是與第 \(i\) 志願的導師連邊跑最大流使得最大流改變,說明找到了一個導師與本身對應。本身的最小的能實現的志願就是 \(i\) 。若是找不到志願i的導師要把與志願i的導師連的邊刪掉。不刪據說會T,一開始覺得要推流,結果並不用。。。
第二問,咱們能夠二分須要高多少名。而後跟第一問作同樣的操做就行。可是咱們須要知道處理完前 \(i\) 個學員的圖是什麼樣子的。
因此要用可持久化網絡流??
由於數據範圍很小,咱們能夠直接把處理完第i個學員後的圖暴力存下。。。
而後這道題就解決了?
還有代碼要寫ios
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; const int INF=1e9; const int N=205; struct edge{ int to,nxt,flow; }e[N*2+N*N*2],hise[N][N*2+N*N*2]; int cnt,head[N*2],hiscnt[N],hishead[N][N*2]; void add_edge(int u,int v,int flow){ cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; e[cnt].flow=flow; head[u]=cnt; cnt++; e[cnt].nxt=head[v]; e[cnt].to=u; e[cnt].flow=0; head[v]=cnt; } int dis[N*2]; bool bfs(int S,int T){ memset(dis,-1,sizeof(dis)); queue<int> q; q.push(S); dis[S]=0; while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(dis[v]==-1&&e[i].flow){ dis[v]=dis[u]+1; q.push(v); } } } if(dis[T]==-1)return false; return true; } int dfs(int u,int T,int f){ if(u==T||f==0)return f; int used=0; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(dis[v]==dis[u]+1&&e[i].flow){ int w=dfs(v,T,min(e[i].flow,f-used)); if(w){ e[i].flow-=w; e[i^1].flow+=w; used+=w; if(used==f)return f; } } } if(used==0)dis[u]=-1; return used; } int ans,hisans[N]; void Dinic(int S,int T){ while(bfs(S,T))ans+=dfs(S,T,INF); } int S,T; void Copy(int now){ for(int i=2;i<=cnt;i++)hise[now][i]=e[i]; hiscnt[now]=cnt; for(int i=S;i<=T;i++)hishead[now][i]=head[i]; hisans[now]=ans; } vector<int> vec[N][N]; int s[N]; int n,m; bool judge(int now,int pre){ for(int i=S;i<=T;i++)head[i]=hishead[pre][i]; cnt=hiscnt[pre]; for(int i=2;i<=hiscnt[pre];i++)e[i]=hise[pre][i]; ans=0; for(int i=1;i<=s[now];i++){ if(vec[now][i].size()==0)continue; for(int j=0;j<vec[now][i].size();j++) add_edge(now,n+vec[now][i][j],1); } Dinic(S,T); if(ans==1)return true; return false; } int read(){ int sum=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();} return sum*f; } int tmp[N]; int main(){ int t=read(),C=read(); while(t--){ cnt=1;memset(head,0,sizeof(head)); memset(tmp,0,sizeof(tmp)); for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) vec[i][j].clear(); n=read();m=read(); S=0,T=n+m+1; for(int i=1;i<=m;i++){ int w=read(); add_edge(i+n,T,w); } for(int i=1;i<=n;i++){ add_edge(S,i,1); for(int j=1;j<=m;j++) vec[i][read()].push_back(j); } for(int i=1;i<=n;i++)s[i]=read(); Copy(0); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(vec[i][j].size()==0)continue; for(int k=0;k<vec[i][j].size();k++) add_edge(i,n+vec[i][j][k],1); ans=0; Dinic(S,T); if(ans==1){ tmp[i]=j;Copy(i);break; } for(int k=vec[i][j].size()-1;k>=0;k--){ int u=i,v=n+vec[i][j][k]; if(bfs(u,v)==0)Dinic(T,v),Dinic(u,S); head[u]=e[head[u]].nxt; head[v]=e[head[v]].nxt; cnt-=2; Dinic(S,T); } } if(tmp[i]==0)Copy(i),tmp[i]=m+1; } for(int i=1;i<=n;i++)printf("%d ",tmp[i]); printf("\n"); for(int i=1;i<=n;i++){ if(tmp[i]<=s[i]){printf("0 ");continue;} int l=1,r=i-1; int Ans=i; while(l<=r){ int mid=(l+r)>>1; if(judge(i,i-mid-1))Ans=mid,r=mid-1; else l=mid+1; } printf("%d ",Ans); } printf("\n"); } return 0; }