CosmicBlocks - TopCoder- 12034 (网络流)

CosmicBlocks - TopCoder- 12034 (网络流)

注意题目定义的同构是存在不同的颜色覆盖关系,而不是存在不同的排列顺序

所以先枚举每一层放了那些颜色,再枚举那些颜色之间有覆盖

每一层的颜色划分数很少,最多可能同时存在的覆盖关系是\(9\)种,枚举复杂度最多是\(2^9\),然后可以\(2^n\cdot n\ \text{dp}\)出拓扑序列的个数

问题在于如何快速又方便地判断对于当前情况是否存在方案

一种方法是上下界网络流

按照层之间的关系,覆盖关系就连\([1,+\infty)\)的边,同时源点向\(1\)层的点连\([0,+\infty)\)的边,每个点都向汇点连\([0,\infty)\)的边

注意由于要限制流过每个点的流量,每个点要拆成两个点中间连\([num_i,num_i]\)的边

最后判断一下有源汇可行流即可

#include<bits/stdc++.h>
using namespace std;

#define Mod1(x) ((x>=P)&&(x-=P))
#define Mod2(x) ((x<0)&&(x+=P))
#define reg register
typedef long long ll;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)

#define pb push_back
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

char IO;
int rd(){
	int s=0;
	int f=0;
	while(!isdigit(IO=getchar())) if(IO=='-') f=1;
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return f?-s:s;
}



static const int N=20,INF=1e8+10;
int n,m,ans,L,R;
int cnt[N],id[N];
vector <int> G[N];
int GS[N];
vector <int> Layer[N];

int Calc_DAG() { // 计算拓扑序列的个数
	static int dp[1<<6];
	int A=(1<<n)-1;
	rep(i,0,A) dp[i]=0;
	dp[0]=1;
	rep(S,0,A-1) rep(i,0,n-1) if((~S&(1<<i)) && (S&GS[i+1])==GS[i+1]) dp[S|(1<<i)]+=dp[S];
	return dp[A];
}

int ind[N];
struct Limited_Flow{ // 有源汇可行流
	static const int M=300;
	int S,T;
	struct Edge{
		int to,nxt,w;
	} e[M];
	int head[N],ecnt;
	void clear(){
		rep(i,1,n*2+4) head[i]=0;
		ecnt=0;
	}
	#define erep(u,i) for(int i=head[u];i;i=e[i].nxt)
	void AddEdge(int u,int v,int w) { e[ecnt]=(Edge){v,head[u],w},head[u]=ecnt++; } 
	void Link(int u,int v,int w){ AddEdge(u,v,w),AddEdge(v,u,0); }
	int dis[N];

	int Bfs(){
		static queue <int> que;
		rep(i,1,T) dis[i]=INF; dis[S]=0,que.push(S);
		while(!que.empty()) {
			int u=que.front(); que.pop();
			erep(u,i) {
				int v=e[i].to,w=e[i].w;
				if(!w || dis[v]<=dis[u]+1) continue;
				dis[v]=dis[u]+1,que.push(v);
			}
		}
		return dis[T]<INF;
	}
	int Dfs(int u,int flowin){
		if(u==T) return flowin;
		int flowout=0;
		erep(u,i) {
			int v=e[i].to,w=e[i].w;
			if(!w || dis[v]!=dis[u]+1) continue;
			int t=Dfs(v,min(flowin-flowout,w));
			e[i].w-=t,e[i^1].w+=t,flowout+=t;
			if(flowin==flowout) break;
		}
		if(!flowout) dis[u]=0;
		return flowout;
	}
	int Dinic(){
		int ans=0;
		while(Bfs()) ans+=Dfs(S,INF);
		return ans;
	}
	int Check(){
		erep(S,i) if(e[i].w) return 0;
		erep(T,i) if(e[i^1].w) return 0;
		return 1;
	}
} Flow;

void Extend_Edge(int u,int v,int L,int R){
	ind[u]-=L,ind[v]+=L;
	Flow.Link(u,v,R-L);
}

int Check(){
	rep(i,1,n*2+4) ind[i]=0;
	Flow.clear();
	rep(i,1,n) Extend_Edge(i*2-1,i*2,cnt[i],cnt[i]);
	rep(i,1,n) if(id[i]==1) Extend_Edge(n*2+1,i*2-1,cnt[i],cnt[i]);
	rep(u,1,n) for(int v:G[u]) Extend_Edge(u*2,v*2-1,1,INF);
	rep(i,1,n) Extend_Edge(i*2,n*2+2,0,INF);
	Extend_Edge(n*2+2,n*2+1,0,INF);

	rep(i,1,n*2+2) {
		if(ind[i]>0) Flow.Link(n*2+3,i,ind[i]);
		if(ind[i]<0) Flow.Link(i,n*2+4,-ind[i]);
	}
	Flow.S=n*2+3,Flow.T=n*2+4;

	Flow.Dinic();
	return Flow.Check();
}

void Dfs_GetDAG(int p) { // dfs枚举覆盖关系
	if(p==n+1) {
		int Ways=Calc_DAG();
		if(Ways<L || Ways>R) return;
		ans+=Check();
		return;
	}
	if(id[p]==m) return Dfs_GetDAG(p+1);
	int n=Layer[id[p]+1].size();
	rep(S,0,(1<<n)-1) {
		rep(i,0,n-1) if(S&(1<<i)) G[p].pb(Layer[id[p]+1][i]),GS[p]|=1<<(Layer[id[p]+1][i]-1);
		Dfs_GetDAG(p+1);
		G[p].clear(),GS[p]=0;
	}
}

void Dfs_Getlayer(int num,int fir,int chosennumber){ // dfs枚举层的情况
	if(chosennumber==n) {
		m=num;
		rep(i,1,m) Layer[i].clear();
		rep(i,1,n) Layer[id[i]].pb(i);
		Dfs_GetDAG(1);
		return;
	}
	rep(i,fir,n) if(!id[i]) {
		id[i]=num;
		Dfs_Getlayer(num,i+1,chosennumber+1);
		id[i]=0;
	}
	if(fir!=1) Dfs_Getlayer(num+1,1,chosennumber);
}

class CosmicBlocks {
public:
	int getNumOrders(vector <int> a, int Min, int Max) {
		L=Min,R=Max;
		n=a.size(),ans=0; rep(i,0,n-1) cnt[i+1]=a[i];
		Dfs_Getlayer(1,1,0);
		return ans;
	}
};

//Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!

posted @ 2020-06-04 13:20  chasedeath  阅读(229)  评论(0编辑  收藏  举报