1781:死亡之树(未AC)

1781:死亡之树

时间限制: 1000 ms 内存限制: 262144 KB
提交数: 99 通过数: 70
【题目描述】

如果一个n个点,m条无向边的图中保证没有重边)的若干个点与连接它们的边组成的一棵树满足n个节点,k
个叶子,则称这棵树为死亡之树。求这个图中有多少棵不同的死亡之树?

叶子的定义:度数为1的节点。

树相同的定义:如果两棵树可以通过摆放,旋转转化为另一棵树的形状,则称之为相同的树。如 与1−2−3为相同的一棵树。
2
/
1 3

【输入】

第一行两个整数n,m,k代表n个点m条边,最终需要有k个叶子;

接下来m行每行两个整数a,b表示a点与b点有一条边。

【输出】

一个整数,代表有多少棵死亡之树。

【输入样例】

3 3 2
1 2
2 3
1 3

【输出样例】

3

【提示】

【样例输入2】

4 6 3
1 2
2 3
3 4
4 1
1 3
2 4

【样例输出2】

4

【数据规模及约定】

对于40%的数据:n≤10,m≤16

对于70%的数据:n≤10,m≤23

对于100%的数据:n≤10,m≤45

思路:
1.算法分析:
发现节点数n<=10,可以用状压,设f[i][j]表示存入节点集合为i,叶节点集合为j,用二进制表示节点状态;

2.初始化:
因为叶子结点定义是入度为1的点,所以当前树的个数一定大于等于2才有可能存在方案,故初始化:
memsetf,0,sizeoff)),f[1<<x)|1<<y)][1<<y)|1<<y)]=1;

3.转移:
枚举当前状态,枚举树中节点x,再枚举与x相连的,不在树内的节点y,则新加入的节点y在树内做叶节点(因为其入度为1),所以状态数为j|1<<y)
特殊的,因为原来的节点x在树中有可能是叶节点,所以应排除x是叶节点的情况,故最终状态为(j^1<<x)|1<<y))
[为了简化,我们可以在枚举y之前先判断x在树中是否是叶节点,如果是,先把x删去。设置一个t表示t=j&1<<x)?j^1<<x),j]

4.去重:
什么情况下会有重复的情况呢,只有在加入边x1 y1,x2 y2时,会出现两种情况:先加1,后加2;先加2,后加1。这样的话只要我们限制更新顺序,就不会有重复的情况发生;

最终状态转移方程:
f[i|1<<y)][t|1<<y)]+=f[i][j]
f[i][j]&&x->y)&&i&i<<x))&&!i&1<<y))&&t<1<<y)))

代码:

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

const int N=10,M=1<<N;
int f[M][M],n,m,k,tot,x,y,t,s,ans;
bool a[N][N];

inline int read)
{
    int s=0;
    bool f=0;
    char ch=' ';
    while!isdigitch))
    {
        f|=ch=='-');
        ch=getchar);
    }
    whileisdigitch))
    {
        s=s<<3)+s<<1)+ch^48);
        ch=getchar);
    }
    return f)?-s):s);
}
inline void writeint x)
{
    ifx<0)
    {
        putchar'-');
        x=-x;
    }
    ifx<10)
    {
        putcharx+'0');
        return;
    }
    writex/10);
    putcharx%10)+'0');
    return;
}
/*
inline void writelnint x)
{
    writex);
    putchar'
');
    return;
}*/

int main)
{
	n=read);m=read),k=read);
	forint i=1;i<=m;i++)
	{
		x=read)-1;
		y=read)-1;
		a[x][y]=a[y][x]=true;
		f[1<<x)|1<<y)][1<<x)|1<<y)]=1;
		//初始时,树中只有两边一点,两个点都是叶子结点
		 
	}
	
	forint i=1;i<=1<<n)-1;i++)//i<=1<<n)-1是因为总共有0~n-1个节点,1<<n-1)的方案数,而下面的j枚举的是叶子节点的状态,为 1~1<<n-1)(至少得有一个叶节点),为了
	//让j-1)=1<<n-1),i=1<<n)-1;
		forint j=i;j;j=j-1)&i) //枚举叶节点,叶节点一定得比树中节点少
		{
			if!f[i][j]) continue;
			forint x=0;x<=n-1;x++)
			{
				if!i&1<<x))) continue;
				t=j&1<<x)?j^1<<x):j;
				forint y=0;y<=n-1;y++)
				{
					if!a[x][y]||i&1<<y))||t>1<<y)));//保证新加入的节点编号一定比树中节点大,有序就可去重  
				}
			}
		 } 
		 
		 
		forint j=1;j<=1<<n)-1;j++)
		{
			s=0;
			t=j;
			whilet)
			{
				s+=t&1;
				t>>1;
			}
			ifs==k) ans+=f[1<<n)-j][j];
		}
		
		writeans);
		return 0;
	 
}

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注