zoukankan      html  css  js  c++  java
  • 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");
    }
    
  • 相关阅读:
    learning scala view collection
    scala
    learning scala dependency injection
    learning scala implicit class
    learning scala type alise
    learning scala PartialFunction
    learning scala Function Recursive Tail Call
    learning scala Function Composition andThen
    System.Threading.Interlocked.CompareChange使用
    System.Threading.Monitor的使用
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15224854.html
Copyright © 2011-2022 走看看