【題目泛做】拆分(網絡流)

CF 212A 數據範圍放大版。


題解:

首先容易發現每個點的 minmax 差不會超過 11,且差爲 11 當且僅當度數不是 tt 的倍數。

換言之,只要保證每個點 ii 分給 jj 的都在 deg/t\lfloor deg/t\rfloordeg/t\lceil deg/t\rceil 即可。證明考慮歸納即可。

那麼第一個思路就很顯然了,考慮歸納,我們先決定哪些邊給到 tt,然後 t--t 考慮下一個問題,顯然可以直接網絡流。

還有一個好點的思路,考慮二分圖邊染色,我們把每個點拆成若干個點,加邊的同時利用增廣保證沒有重複顏色即可。


代碼1(網絡流):

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int N=6e2+7,M=1e6+7;

int deg[N];
int bel[M],rec[M];
int a,b,m,k;

int S,T;
int el[N],nx[M],to[M],cap[M],ec=1;
void adde(int u,int v,int c){
	nx[++ec]=el[u],el[u]=ec,to[ec]=v,cap[ec]=c;
	nx[++ec]=el[v],el[v]=ec,to[ec]=u,cap[ec]=0;
}

int lev[N],gap[N],cur[N],finished;
void BFS(){
	memset(lev,0,sizeof lev);
	memset(gap,0,sizeof gap);
	std::queue<int> q;q.push(T);lev[T]=gap[1]=1;
	while(!q.empty()){
		int u=q.front();q.pop();cur[u]=el[u];
		for(int re e=el[u];e;e=nx[e])
			if(!bel[e]&&!lev[to[e]]){
				lev[to[e]]=lev[u]+1;
				++gap[lev[to[e]]];
				q.push(to[e]);
			}
	}finished=lev[S]==0;
}

int dfs(int u,int flow){
	if(u==T)return flow;int ans=0;
	for(int &e=cur[u];e;e=nx[e])
		if(!bel[e]&&cap[e]&&lev[to[e]]+1==lev[u]){
			int dlt=dfs(to[e],std::min(flow-ans,cap[e]));
			cap[e]-=dlt;cap[e^1]+=dlt;
			if((ans+=dlt)==flow)return ans;
		}
	if(!--gap[lev[u]])finished=true;
	++gap[++lev[u]];cur[u]=el[u];
	return ans;
}

int vs[N],idx;

bool fix_flow(int u){
	if(vs[u]==idx)return false;
	vs[u]=idx;int eu=u+m;
	if(cap[eu<<1|1]>deg[u]/k){
		--cap[eu<<1|1];
		++cap[eu<<1];
		return true;
	}
	for(int re e=el[u];e;e=nx[e])
		if(!bel[e]&&rec[e]==cap[e]&&vs[to[e]]!=idx){
			vs[to[e]]=idx;int v=to[e];
			for(int re r=el[v];r;r=nx[r])
				if(!bel[r]&&rec[r]!=cap[r]&&fix_flow(to[r])){
					int w=cap[r]<rec[r]?-1:1;
					cap[r]-=w,cap[r^1]+=w;
					cap[e]-=w,cap[e^1]+=w;
					return true;
				}
		}
	return false;
}

void Flow(){
	BFS();while(!finished)dfs(S,1e9);
	for(int re i=1;i<=a+b;++i)
		while(cap[(i+m)<<1|1]<deg[i]/k){
			vs[S]=vs[T]=++idx;
			assert(fix_flow(i));
			++cap[(i+m)<<1|1];
			--cap[(i+m)<<1];
		}
}

void Main(){
	scanf("%d%d%d%d",&a,&b,&m,&k);
	S=0,T=a+b+1;
	for(int re i=1;i<=m;++i){
		int u,v;scanf("%d%d",&u,&v);
		++deg[u],++deg[v+a];adde(u,v+a,1);
	}
	for(int re i=1;i<=a;++i)
		adde(S,i,0);
	for(int re j=1;j<=b;++j)
		adde(j+a,T,0);
	for(;k;--k){
		for(int re i=1;i<=a+b;++i)
			cap[(i+m)<<1]=(deg[i]+k-1)/k,
			cap[(i+m)<<1|1]=0;
		for(int re i=2;i<=ec;++i)
			rec[i]=cap[i];
		Flow();
		for(int re i=2;i<=m+m+1;++i)
			if(rec[i]!=cap[i]){
				--deg[to[i]];
				bel[i]=k;
			}
	}
	for(int re i=1;i<=m;++i)
		cout<<bel[i<<1]<<" ";
}

inline void file(){
#ifdef zxyoi
	freopen("divide.in","r",stdin);
#endif
	int size=40<<20;//40M
    __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//提交用這個  
}signed main(){file();Main();exit(0);}

代碼2(二分圖邊染色):

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int N=3e2+7,M=1e5+7;

int c0,c1;
int nx[2][N+N][N];
void dfs(int o,int x,int y,int cx,int cy){
	int to=nx[o^1][y][cx];
	nx[o][x][cx]=y;
	nx[o^1][y][cx]=x;
	if(!to){
		nx[o^1][y][cy]=0;
		return;
	}dfs(o^1,y,to,cy,cx);
}
int a,b,m,k,ans[M];
int sz[2][N],id[2][N];
int eid[N+N][N+N];

void Main(){
	scanf("%d%d%d%d",&a,&b,&m,&k);
	std::fill(sz[0]+1,sz[0]+a+1,k);
	std::fill(sz[1]+1,sz[1]+b+1,k);
	for(int re i=1;i<=m;++i){
		int u,v;scanf("%d%d",&u,&v);
		if(sz[0][u]==k)
			sz[0][u]=0,id[0][u]=++c0;
		if(sz[1][v]==k)
			sz[1][v]=0,id[1][v]=++c1;
		++sz[0][u],u=id[0][u];
		++sz[1][v],v=id[1][v];
		eid[u][v]=i;int cu=1,cv=1;
		for(;nx[0][u][cu];++cu);
		for(;nx[1][v][cv];++cv);
		if(cu==cv){
			nx[0][u][cu]=v;
			nx[1][v][cv]=u;
		}else dfs(0,u,v,cu,cv);
	}
	for(int re i=1;i<=c0;++i)
		for(int re c=1;c<=k;++c)
			if(nx[0][i][c])ans[eid[i][nx[0][i][c]]]=c;
	for(int re i=1;i<=m;++i)
		cout<<ans[i]<<" ";
}

inline void file(){
#ifdef zxyoi
	freopen("divide.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章