题意:
已知 n 个人,知道 n 个人的实力,了解到两两比赛的结果,
现在让你安排 n 个人的比赛顺序。让编号 为 k 的人顺利。问你有几种安排的顺序。
安排的顺序要满足竞赛树的高度最小。
思路:
树上 + 状压 DP。
这里要考虑一下树的高度。
严格根据高度来 DP。
这里面有一个for循环,可以找到一个状态中 所有 1 的情况。
#include<bits/stdc++.h>
#define popcnt __builtin_popcount //这个是查看 一个数中有多少个 1.
using namespace std;
const int N = 20;
int a[N][N],f[N][N][1<<17];
int n,k;
int dfs(int u, int h, int s){
if (popcnt(s) == 1) return 1;
if (!h || ((1<<h) < popcnt(s))) return 0;
int &ans = f[u][h][s];
if (ans != -1) return ans;
ans = 0;
for (int t = s & (s-1); t; t = (t-1)&s)
if (t & (1 << u)){
for (int j = 0; j < n; ++j)
if ((~t&(1<<j)) && (s &(1<<j)) && a[u][j]) ans += dfs(u,h-1,t)*dfs(j,h-1,s^t);
}
return ans;
}
int main(){
scanf("%d%d",&n,&k);
k--;
for (int i = 0; i < n; ++i)
for (int j =0; j < n; ++j)
scanf("%d",&a[i][j]);
int h = 0;
while( (1<<h) < n) h++;
memset(f,-1,sizeof f);
printf("%d\n",dfs(k,h,(1<<n)-1));
return 0;
}