CF611H New Year and Forgotten Tree
Posted flyfeather6
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}
以上是关于CF611H New Year and Forgotten Tree的主要内容,如果未能解决你的问题,请参考以下文章
CF 750C New Year and Rating(思维题)
CF1284E New Year and Castle Construction
CF1284E New Year and Castle Construction
CF1279F New Year and Handle Change 题解