[BZOJ5251][二分图匹配]九省联测:劈配

版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/87926123

BZOJ5251

原题解

二分图匹配,若失败,则继续枚举下一志愿,若成功则这就是第一问答案,这样的话,第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;
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/87926123