【网络流】【贪心】「九省联考 2018」秘密袭击

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/87969257

题意:

太鬼扯了自己去看


分析:

很暴力的贪心+网络流check

这种多点共同选择的问题一定要联想到网络流

第一问每次在残留网络上跑看能不能跑出新流量,能跑出即为当前层数。

第二问用二分,每次重建图跑就好了,不用非要去存图,太耗内存而且代码复杂度也差不多。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 510
#define INF 0x3FFFFFFF
using namespace std;
vector<int> a[MAXN],w[MAXN],rev[MAXN];
int s,t,tot;
void add_edge(int u,int v,int val){
	a[u].push_back(v);
	a[v].push_back(u);
	w[u].push_back(val);
	w[v].push_back(0);
	rev[u].push_back(a[v].size()-1);
	rev[v].push_back(a[u].size()-1);
}
int T,C,n,m;
int b[MAXN],S[MAXN],ans[MAXN];
vector<int> tar[MAXN][MAXN];
void build_edge(int x,int y){
	for(int i=0;i<int(tar[x][y].size());i++)
		add_edge(x,tar[x][y][i]+n,1);
}
void dele_edge(int x,int y){
	for(int i=0;i<int(tar[x][y].size());i++){
		a[tar[x][y][i]+n].pop_back();
		w[tar[x][y][i]+n].pop_back();
		rev[tar[x][y][i]+n].pop_back();
	}
	int sd=int(tar[x][y].size());
	for(int i=1;i<=sd;i++)
		a[x].pop_back(),w[x].pop_back(),rev[x].pop_back();
}
void clear_it(int x,int i){
	w[x][i]=w[a[x][i]][rev[x][i]]+w[x][i];
	w[a[x][i]][rev[x][i]]=0;	
}
void clear_edge(){
	for(int i=0;i<tot;i++)
		for(int j=0;j<int(a[i].size());j++)
			if(a[i][j]>i)
				clear_it(i,j);
}
int d[MAXN],g[MAXN];
int dfs(int x,int f){
	if(x==t)
		return f;
	int less=f;
	for(int i=0;i<int(a[x].size())&&less;i++)
		if(w[x][i]&&d[a[x][i]]==d[x]-1){
			int res=dfs(a[x][i],min(less,w[x][i]));
			less-=res;
			w[x][i]-=res;
			w[a[x][i]][rev[x][i]]+=res;
			if(d[s]>tot)
				return f-less;
		}
	if(less==0)
		return f;
	g[d[x]]--;
	if(g[d[x]]==0){
		d[s]=tot+1;
		return f-less;	
	}
	d[x]=tot+1;
	for(int i=0;i<int(a[x].size());i++)
		if(w[x][i])
			d[x]=min(d[x],d[a[x][i]]);
	d[x]++;
	g[d[x]]++;
	return f-less;
}
int maxf(){
	g[0]=tot;
	memset(d,0,sizeof d);
	int res=0;
	while(d[s]<=tot)
		res+=dfs(s,INF);	
//	clear_edge();
	return res;
}
bool check(int x,int len){
	int sum=1;
	clear_edge();
	for(int i=1;i<len;i++) {build_edge(i,ans[i]);sum+=(ans[i]!=(m+1));}
	for(int i=1;i<=S[x];i++) build_edge(x,i);
	int res=maxf();
	for(int i=S[x];i>=1;i--) dele_edge(x,i);
	for(int i=len-1;i>=1;i--) dele_edge(i,ans[i]);
	return res==sum;
}
int b_search(int x){
	if(ans[x]<=S[x])
		return 0;
	int l=1,r=x-1,res=x;
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(x,mid)){
			res=x-mid;
			l=mid+1;
		}
		else
			r=mid-1;	
	}
	return res;
}
void Print_edges(){
	PF("-------------\nPrint edges:\n");
	for(int i=0;i<tot;i++){
		PF("%d:\n",i);
		for(int j=0;j<int(a[i].size());j++)
			PF("{%d %d}",a[i][j],w[i][j]);
		PF("\n");
	}
	PF("Print finished!\n---------------\n");
}	
int main(){
	SF("%d%d",&T,&C);
	int x;
	while(T--){
		SF("%d%d",&n,&m);
		s=0;
		t=n+m+1;
		tot=t+1;
		for(int i=1;i<=m;i++){
			SF("%d",&b[i]);
			add_edge(i+n,t,b[i]);
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m+1;j++)
				tar[i][j].clear();
			for(int j=1;j<=m;j++){
				SF("%d",&x);
				if(x) tar[i][x].push_back(j);
			}
		}
		for(int i=1;i<=n;i++){
			SF("%d",&S[i]);
			ans[i]=m+1;
			add_edge(s,i,1);
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				build_edge(i,j);
				if(maxf()==1){
					ans[i]=j;
					break;
				}
				dele_edge(i,j);
			}
		}
		for(int i=1;i<=n;i++)
			PF("%d ",ans[i]);
		PF("\n");
		for(int i=n;i>=1;i--)
			dele_edge(i,ans[i]);
		for(int i=1;i<=n;i++)
			PF("%d ",b_search(i));	
		PF("\n");
		for(int i=0;i<tot;i++)
			a[i].clear(),w[i].clear(),rev[i].clear();
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/87969257