• CF611H New Year and Forgotten Tree


    一、题目

    点此看题

    二、解法

    看来什么东西反向构造都难

    首先不难想到把点按位数染色,一个显然的 ( t observation) 是:每种颜色的点等价。

    考虑适当枚举简化问题,可以在每个颜色中选出一个代表点,然后把这些代表点做生成树,剩下的点接在这些代表点上,这是因为如果存在解,那么就存在其他点之连接代表点的解。可以用调整法简单证明,如果其他点接在非关键点上,那么调整到关键点上依然合法。

    反正颜色数很小,可以枚举 ( t prufer) 序列来确定关键点的生成树。然后把每种颜色的点放在一起考虑,边 ((i,j)) 可以通过和颜色 (j) 关键点的连边解决一个颜色 (i) 中的点,也可以通过和颜色 (i) 关键点连边解决一个颜色 (j) 中的点。

    你发现这就是一个二分图匹配模型,把边建在 (X) 部,把颜色建在 (Y) 部,跑出残量网络即可构造出解。

    三、总结

    本题直接入手很不好做,需要通过适当枚举简化问题。

    最关键的地方其实是选出关键点,得到这个思路需要你对树形结构有一定的理解,树可以通过先构造基本树在把其他点接在这个树上完成,因为每种颜色的点等价才想到用颜色来构建基本树。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int M = 105;
    const int inf = 0x3f3f3f3f;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,b[8][8],num[8],p[8],a[8];
    //the part of dinic
    int cnt,tot,S,T,f[M],dis[M];
    struct edge
    {
    	int v,c,next;
    }e[M*M];
    void add(int u,int v,int c)
    {
    	e[++tot]=edge{v,c,f[u]},f[u]=tot;
    	e[++tot]=edge{u,0,f[v]},f[v]=tot;
    }
    int bfs()
    {
    	queue<int> q;
    	memset(dis,0,sizeof dis);
    	dis[S]=1;q.push(S);
    	while(!q.empty())
    	{
    		int u=q.front();q.pop();
    		if(u==T) return 1;
    		for(int i=f[u];i;i=e[i].next)
    		{
    			int v=e[i].v;
    			if(!dis[v] && e[i].c>0)
    			{
    				dis[v]=dis[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	return 0;
    }
    int dfs(int u,int ept)
    {
    	if(u==T) return ept;
    	int flow=0,tmp=0;
    	for(int i=f[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(dis[v]==dis[u]+1 && e[i].c>0)
    		{
    			tmp=dfs(v,min(ept,e[i].c));
    			e[i].c-=tmp;
    			e[i^1].c+=tmp;
    			flow+=tmp;
    			ept-=tmp;
    			if(!ept) break;
    		}
    	}
    	return flow;
    }
    int dinic()
    {
    	int ans=0;
    	while(bfs()) ans+=dfs(S,inf);
    	return ans;
    }
    //check the tree
    void check()
    {
    	tot=1;cnt=S=0;
    	for(int i=0;i<M;i++) f[i]=0;
    	//use prufer to build tree
    	int q[8]={},c[8][8]={},d[8]={}
    	,vis[8]={},id[8][8]={};
    	a[m-1]=m;
    	for(int i=1;i<m;i++) d[a[i]]++;
    	for(int i=1;i<m;i++)
    	{
    		int p=0;
    		for(int j=1;j<=m;j++)
    			if(!vis[j] && !d[j])
    				p=j;
    		vis[p]=1;d[a[i]]--;
    		c[min(p,a[i])][max(p,a[i])]++;
    	}
    	for(int i=1;i<=m;i++)
    		for(int j=i;j<=m;j++)
    			id[i][j]=++cnt;
    	T=cnt+1+m;
    	for(int i=1;i<=m;i++)
    		for(int j=i;j<=m;j++)
    		{
    			if(c[i][j]>b[i][j]) return ;
    			add(S,id[i][j],b[i][j]-c[i][j]);
    			add(id[i][j],cnt+i,inf);
    			add(id[i][j],cnt+j,inf);
    		}
    	for(int i=1;i<=m;i++)
    		add(cnt+i,T,num[i]-1);
    	if(dinic()<n-m) return ;
    	for(int i=1;i<=m;i++) q[i]=p[i];
    	for(int i=1;i<=m;i++)
    		for(int j=1;j<=m;j++) if(c[i][j])
    			printf("%d %d
    ",p[i],p[j]);
    	for(int i=1;i<=m;i++)
    		for(int j=i;j<=m;j++)
    		{
    			int u=id[i][j];
    			for(int w=f[u];w;w=e[w].next)
    			{
    				int v=e[w].v,c=e[w^1].c;
    				if(v==S) continue;
    				if(v-cnt==i) while(c--)
    					printf("%d %d
    ",++q[i],p[j]);
    				else while(c--)
    					printf("%d %d
    ",++q[j],p[i]);
    			}
    		}
    	exit(0);
    }
    //fuck all prufer
    void zxy(int x)
    {
    	if(x==m-1)
    	{
    		check();
    		return ;
    	}
    	for(int i=1;i<=m;i++)
    	{
    		a[x]=i;
    		zxy(x+1);
    	}
    }
    signed main()
    {
    	n=read();
    	for(int i=1;i<n;i++)
    	{
    		char s[10],t[10];
    		scanf("%s%s",s,t);
    		int l1=strlen(s),l2=strlen(t);
    		b[min(l1,l2)][max(l1,l2)]++;
    	}
    	for(int i=1;i<=n;i*=10) p[++m]=i;
    	for(int i=1;i<m;i++) num[i]=p[i+1]-p[i];
    	num[m]=n-p[m]+1;
    	if(m==1)
    	{
    		if(b[1][1]!=n-1) puts("-1");
    		else
    		{
    			for(int i=1;i<n;i++)
    				printf("%d %d
    ",i,i+1);
    		}
    		return 0;
    	}
    	zxy(1);
    	puts("-1");
    }
    
  • 相关阅读:
    leetcode 75 颜色分类 A
    leetcode525连续数组 A
    WCF无身份验证配置
    三读设计模式
    EntityFrameWork+Oracle学习笔记搭配环境(一)
    EntityFrameWork+Oracle学习笔记DBfirst(二)
    用Python解答百度测试开发算法面试题
    Python实现采集wordpress整站数据的爬虫
    吾八哥学Python(六):运算符与表达式
    吾八哥学Python(四):了解Python基础语法(下)
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15224854.html
Copyright © 2020-2023  润新知