版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/87926123
二分图匹配,若失败,则继续枚举下一志愿,若成功则这就是第一问答案,这样的话,第ii张图就会是满足前ii个人志愿的剩余图,这在第二问会用到,所以我们要保留下来。
然后第二问,同样是对学员一个一个处理,二分他需要前进的名次,然后直接使用原来的剩余图进行加边,我们可以把他前si的志愿全部一起加上(这显然是对的,一起做可以节省大量时间),然后开始增广,同样的,成功说明他可以少前进一点,失败则需要前进更多。
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=410,M=80100,INF=1000000000;
int n,m,k,ans,tot;
int S,T,b[N],dis[N],head[N],q[M];
int nxt[M],vis[M],c[M],res[N];
vector<int>V[N][N];
void add(int u,int v,int w){
vis[++tot]=v;c[tot]=w;nxt[tot]=head[u];head[u]=tot;
vis[++tot]=u;c[tot]=0;nxt[tot]=head[v];head[v]=tot;
}
bool bfs(){
for(int i=0;i<=T;i++) dis[i]=0;
dis[S]=1;q[1]=S;
int st=0,ed=1;
while(st!=ed){
int x=q[++st];
for(int k,i=head[x];i;i=nxt[i]) if(!dis[k=vis[i]] && c[i]) dis[k]=dis[x]+1,q[++ed]=k;
}
return dis[T];
}
int dfs(int x,int lim){
if (x==T) return lim;
int cc=0;
for(int k,i=head[x];i;i=nxt[i]) if (dis[k=vis[i]]==dis[x]+1 && c[i]){
int t=dfs(k,min(lim-cc,c[i]));
c[i]-=t;c[i^1]+=t;cc+=t;
if (cc==lim) return lim;
}
if (!cc) dis[x]=-1;
return cc;
}
bool work(int x,int l,int r){
for(int i=l;i<=r;i++)
for(int j=0;j<=(int)V[x][i].size()-1;j++) add(x,V[x][i][j]+n,1);
if(bfs()) {dfs(S,INF);return 1;}
return 0;
}
int main(){
int t=read(),mp=read();
while(t--){
n=read();m=read();
for(int i=1;i<=m;i++) b[i]=read();
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) V[i][j].clear();
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) k=read(),V[i][k].push_back(j);
tot=1;S=n+m+1;T=n+m+2;
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++) add(S,i,1);
for(int i=1;i<=m;i++) add(i+n,T,b[i]);
for(int i=1;i<=n;i++){
for(res[i]=1;res[i]<=m;res[i]++) if(work(i,res[i],res[i])) break;
cout<<res[i]<<" ";
}
puts("");
for(int i=1;i<=n;i++){
memset(head,0,sizeof(head));
k=read();ans=i;tot=1;S=n+m+1;T=n+m+2;
for(int j=1;j<=n;j++) add(S,j,1);
for(int j=1;j<=m;j++) add(j+n,T,b[j]);
if(!work(i,1,k)) {cout<<i<<" ";continue;}
for(int j=1;--ans;j++){
if (res[j]>m) continue;
if (!work(j,res[j],res[j])) break;
}
cout<<ans<<" ";
}
puts("");
}
return 0;
}