【BZOJ5251】【九省联考2018】—劈配(网络流)

传送门

据说匈牙利变一下跑的贼快?
反正我选择 d i n i c dinic dinic
第一次跑下来 b z o j bzoj bzoj上倒数第二
嘤嘤嘤

第一问很好做
考虑依次枚举每个人,枚举每种志愿
跑网络流,看有没有流量
如果有的话显然是有满足方案的
没有最好把这一种的边给删了,因为反正以后也没有用了

第二问考虑可以二分
然后把这个人提到前面去,连边看能不能跑出来

为了方便写了个结构体存边
虽然跑得慢但代码还是清真吧

#include
using namespace std;
#define ll long long
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int inf=1e9;
const int M=10006;
const int N=205;
int str,des,n,m;
int T,c,mx[N],f[N],ans[N],hp[N];
vector<int> e[N][N];
struct Graph{
	int adj[M],nxt[M<<1],to[M<<1],cap[M<<1],tp[M<<1],lev[M<<1],cnt;
	Graph(int _cnt=1){cnt=_cnt;}
	inline void init(){
		memset(adj,0,sizeof(adj)),cnt=1;
	}
	inline void addedge(int u,int v,int w){
		nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,cap[cnt]=w;
		nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u,cap[cnt]=0;
	}
	inline void deletedge(int u,int v){
		adj[u]=nxt[adj[u]],cnt--;
		adj[v]=nxt[adj[v]],cnt--;
	}
	inline bool bfs(){
		memset(lev,-1,sizeof(lev));
		queue<int> q;
		lev[str]=0,q.push(str);
		while(!q.empty()){
			int u=q.front();q.pop();
			for(int e=adj[u];e;e=nxt[e]){
				int v=to[e];
				if(cap[e]>0&&lev[v]==-1){
					lev[v]=lev[u]+1,q.push(v);
					if(v==des){
						return true;
					}
				}
			}
		}
		return false;
	}
	int dinic(int u,int flow){
		if(u==des)return flow;
		int res=0;
		for(int &e=tp[u];e;e=nxt[e]){
			int v=to[e];
			if(cap[e]>0&&lev[v]==lev[u]+1){
				int now=dinic(v,min(flow-res,cap[e]));
				res+=now,cap[e]-=now,cap[e^1]+=now;
				if(flow==res){
					
					return res;
				}
			}
		}
		return res;
	}
}G[N];
inline void solve1(){
	for(int i=1;i<=n;i++){
		G[i]=G[i-1];
		G[i].addedge(str,i,1);
		for(int j=1;j<=m;j++){
			for(int p=0;p<e[i][j].size();p++)
				G[i].addedge(i,e[i][j][p]+n,1);
			if(G[i].bfs()){
				memcpy(G[i].tp,G[i].adj,sizeof(G[i].adj));
				G[i].dinic(str,inf);
				ans[i]=j;break;
			}
			for(int p=0;p<e[i][j].size();p++)
				G[i].deletedge(i,e[i][j][p]+n);
		}
	}
	for(int i=1;i<=n;i++){
		if(!ans[i])ans[i]=m+1;
		cout<<ans[i]<<" ";
	}puts("");
}
inline bool check(int u,int pt){
	Graph tg=G[pt-1];
	tg.addedge(str,u,1);
	for(int i=1;i<=f[u];i++)
		for(int j=0;j<e[u][i].size();j++)
			tg.addedge(u,e[u][i][j]+n,1);
		
	if(tg.bfs())return 1;
	else return 0;
}
inline void solve2(){
	for(int i=1;i<=n;i++){
		if(ans[i]<=f[i])continue;
		hp[i]=inf;
		int l=1,r=i-1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(check(i,mid))hp[i]=mid,l=mid+1;
			else r=mid-1;
		}
		if(hp[i]&&hp[i]!=inf)hp[i]=i-hp[i];
	}
	for(int i=1;i<=n;i++)cout<<((hp[i]==inf)?(i):(hp[i]))<<" ";
	puts("");
}
inline void clear(){
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			e[i][j].clear();
	memset(ans,0,sizeof(ans));
	memset(hp,0,sizeof(hp));
	G[0].init();
}
inline void solve(){
	clear();
	n=read(),m=read();
	str=n+m+1,des=str+1;
	for(int i=1;i<=m;i++){
		mx[i]=read();
		G[0].addedge(i+n,des,mx[i]);
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			int p=read();if(p)
			e[i][p].push_back(j);
		}
	for(int i=1;i<=n;i++)f[i]=read();
	solve1(),solve2();
}
int main(){
	T=read(),c=read();
	while(T--)solve();
}

你可能感兴趣的:(最大流)