题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4013
题意:给定一棵树,求不同的子树的个数。
思路:枚举每个点集,DFS求最小表示。对于某一种情况,若有一次得到的表示以前没有,答案加1。你可能会想,如果这种情况可以得到一棵森林呢,这样的话森林中的每棵树在之前肯定插入了,因为你是按照状态枚举的,单棵树的状态肯定小于森林的状态。
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int g[15][15],n,C,num=0,visit[15];
set<string> S;
string DFS(int u,int pre)
{
int i;
string s="0";
vector<string> V;
for(i=0;i<n;i++) if(g[u][i]&&i!=pre&&visit[i])
V.push_back(DFS(i,u));
sort(V.begin(),V.end());
for(i=0;i<V.size();i++) s+=V[i];
s+="1";
return s;
}
void deal()
{
int i,j,flag,ans=0;
string str;
for(i=0;i<(1<<n);i++)
{
memset(visit,0,sizeof(visit));
for(j=0;j<n;j++) if(i&(1<<j)) visit[j]=1;
flag=0;
for(j=0;j<n;j++) if(visit[j])
{
str=DFS(j,-1);
if(S.find(str)==S.end()) flag=1,S.insert(str);
}
ans+=flag;
}
printf("%d\n",ans);
}
int main()
{
for(scanf("%d",&C);C--;)
{
scanf("%d",&n);
memset(g,0,sizeof(g));
int i,u,v;
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
u--;v--;
g[u][v]=g[v][u]=1;
}
S.clear();
printf("Case #%d: ",++num);
deal();
}
return 0;
}