CF611H New Year and Forgotten Tree

题意

给定你一棵树,结点编号为 (1-n) 现在用问号的个数代表每个节点编号那个数字的长度,请你还原这一颗树,任意输出一个方案,可能无解。
传送门
(n<2 imes 10^5)

思路

首先位数相同的点之间的边随便连。

因此剩下的就是一些不同色的点,要求 (a[i][j]=x) ,求连边方案(同色间不能连)。

如果有解则一定存在一种方案,是将每种位数拿一个点出来,连成一个生成树,然后把其它的点连到生成树上的点。

爆搜生成树的形态,然后用网络流求匹配判断是否存在方案。即对于 (a[i][j]) 可能是小 (i) 连向生成树中的 (j) 色或者反过来,两种加起来刚好满足时,对于两种情况的分配。

输出答案(注意细节)

#include <bits/stdc++.h>
using std::queue;
const int INF=200000,N=100;
int n,a[100],f[100][100],w,fa[100],m,b[100],tot,s,t,last[N],to[N<<2],Next[N<<2],edge,flow[N<<2];
int deep[N],sum,c[N];
queue <int> q;
char s1[100],s2[110];
struct ed{
	int x,y;
}e[100];
int cw(int x){
	int cnt=0;
	while (x) x=x/10,cnt++;
	return cnt;
}
int find(int x){
	if (fa[x]==x) return x;
	fa[x]=find(fa[x]);
	return fa[x];
}
bool p(){//判断是否是树 
	for (int i=1;i<=w;i++) fa[i]=i;
	for (int i=1;i<=m;i++){
		if (b[i]==1){
			int fx=find(e[i].x),fy=find(e[i].y);
			if (fx==fy) return false;
			fa[fx]=fy;
		}
	}
	return true;
}
int cal(int x){return x&1?x+1:x-1;}
void add(int x,int y,int z){
	to[++edge]=y;
	Next[edge]=last[x];
	last[x]=edge;
	flow[edge]=z;
}
void Add(int x,int y,int z){add(x,y,z),add(y,x,0);}
bool bfs(){
	memset(deep,0,sizeof(deep));
	deep[s]=1;
	q.push(s);
	while (!q.empty()){
		int x=q.front();
		q.pop();
		for (int i=last[x];i;i=Next[i])
			if (flow[i] && !deep[to[i]]){
				deep[to[i]]=deep[x]+1;
				q.push(to[i]);
			}
	}
	return deep[t];
}
int Dfs(int x,int now){
	if (x==t) return now;
	for (int i=last[x];i;i=Next[i]){
		if (deep[to[i]]<=deep[x]) continue;
		if (!flow[i]) continue;
		int di=Dfs(to[i],std::min(now,flow[i]));
		if (di){
			flow[i]-=di;
			flow[cal(i)]+=di;
			return di;
		}
	}
	return 0;
}
void Printf(){
	for (int i=1;i<=m;i++)
		if (b[i]) printf("%d %d
",c[e[i].x],c[e[i].y]);//主生成树 
	for (int i=1;i<=w;i++)//同位数 
		for (int j=c[i+1]-1;j>=c[i+1]-f[i][i];j--) printf("%d %d
",j,j-1);
	for (int x=1;x<=w;x++){
		int now=c[x]+1;
		for (int i=last[x];i;i=Next[i])
			if (to[i]-w>0 && to[i]-w<=m){
				int u=e[to[i]-w].x+e[to[i]-w].y-x;
				for (int j=now;j<now+flow[i];j++)
					printf("%d %d
",c[u],j);
				now=now+flow[i];
			}
	}
}
void solve(){
	for (int i=1;i<=m;i++)
		f[e[i].x][e[i].y]-=b[i];
	memset(last,0,sizeof(last));
	edge=0; 
	for (int i=1;i<=w;i++)
		Add(i,t,a[i]-1-f[i][i]);
	for (int i=1;i<=m;i++)
		if (f[e[i].x][e[i].y]){
			Add(i+w,e[i].x,INF);
			Add(i+w,e[i].y,INF);
			Add(s,i+w,f[e[i].x][e[i].y]);
		}
	int ans=0;
	while (bfs())
		while (int di=Dfs(s,INF)) ans+=di;
	if (ans==sum){
		Printf();
		exit(0);
	}
	for (int i=1;i<=m;i++)
		f[e[i].x][e[i].y]+=b[i];
}
void dfs(int x,int y){//找生成树 
	if (y==w-1){
		if (p()) solve();
		return;
	}
	if (x>m) return;
	b[x]=0,dfs(x+1,y);
	if(f[e[x].x][e[x].y])b[x]=1,dfs(x+1,y+1);
}
int main(){
	scanf("%d",&n);
	w=cw(n);
	for (int i=1;i<n;i++){
		scanf("%s%s",&s1,&s2);
		int w1=strlen(s1),w2=strlen(s2);
		if (w1>w2) std::swap(w1,w2);
		f[w1][w2]++;
	}
	int j=1;
	for (int i=1;i<w;i++,j=j*10) a[i]=j*9,c[i]=j;
	if (w==1) a[w]=n;
	else a[w]=n-j+1;
	c[w+1]=n+1;
	c[w]=j;
	sum=n-1-(w-1);
	for (int i=1;i<=w;i++)  
		if (f[i][i]>=a[i]){
			puts("-1");
			return 0;
		}else sum-=f[i][i];
	m=0;
	for (int i=1;i<=w;i++)
		for (int j=i+1;j<=w;j++) e[++m]={i,j};
	s=w+m+1,t=w+m+2;
	dfs(1,0);
	puts("-1");
	return 0;
}
原文地址:https://www.cnblogs.com/flyfeather6/p/12213027.html