一道dp题
一棵赛程树是一棵以m为根的特殊的二叉树
/**
意思是每一个非叶子节点都有2个儿子
**/
dp[i][s][h]
三位状态中
i表示这棵子树的根为i
s表示这棵子树中含有的节点状态
h表示这棵子树的高度
dp[i][s][h]=∑dp[j][s’][h-1]*dp[i][s-s’][h-1]
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int head[16];
int next[405];
int to[405];
int cnt;
int calc[1<<16];
int dp[16][1<<16][8];
inline void dfs(int id,int s,int h)
{
if(dp[id][s][h]!=-1)
{
return ;
}
if((1<<h)<calc[s])
{
dp[id][s][h]=0;
return ;
}
if(s==(1<<id))
{
dp[id][s][h]=1;
return ;
}
if(h==0)
{
dp[id][s][h]=0;
return ;
}
dp[id][s][h]=0;
int i,j;
for(i=s&(s-1);i;i=(i-1)&s)
{
if((1<<id)&i)
{
continue;
}
for(j=head[id];j!=-1;j=next[j])
{
if(!((1<<to[j])&s))
{
continue;
}
if(!((1<<to[j])&i))
{
continue;
}
dfs(id,s-i,h-1);
dfs(to[j],i,h-1);
dp[id][s][h]+=dp[id][s-i][h-1]*dp[to[j]][i][h-1];
}
}
}
int main()
{
int i,j,id,num;
while(scanf("%d %d",&n,&m)!=EOF)
{
memset(head,-1,sizeof(head));
cnt=0;
memset(dp,-1,sizeof(dp));
memset(calc,0,sizeof(calc));
id=0;num=1;
while(num<n)
{
num*=2;
id++;
}
m--;
for(i=0;i<(1<<n);i++)
{
for(j=0;j<n;j++)
{
if((1<<j)&i)
{
calc[i]++;
}
}
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
scanf("%d",&num);
if(num==1)
{
next[cnt]=head[i];
to[cnt]=j;
head[i]=cnt;
cnt++;
}
}
}
dfs(m,(1<<n)-1,id);
cout<<dp[m][(1<<n)-1][id]<<endl;
}
return 0;
}