【Gym100837F】制御トーナメント(検索プルーン様の圧力DP)

トピックリンク

不注意な

既存の\(N \)個人的な戦いのゲーム、任意の2人の関係の結果を知っているゲームをプレイ。
必要と最小深さ、根場合は\(M \)ツリーのレースの数を。

満たす\(1 \ルM \ル N \ル16 \)

思考

考慮に入れると、\(N \)などの小さな範囲、圧力は、暴力的な検索のようではありません。
ステータスに関係なく\(DP [S] [U ] [D]は\) 点集合を表していない\(S \)構成サブツリー、\(U \)何より深い根のため、(D \)\番号スキームを。
それを転送する\(DP [S] [U] [D] = Dpの[S '] [U] [D] + Dpの[S-S'] [V] [D] \)。ここで\(U \ )打つことができる(V \)\

この複雑性はあるが、(O(3 ^ N \ N ^ 2回)\)\、メモリを考慮すると、状態の保存役に立たない検索となります。

最小深与えられた問題の条件を考慮し、木の深さがなければなりません(\ \ rceil \ \右IOG2(N)lceil \左)\、その2つのサブツリーが特定の深さを超えることはありません(\ \ IOG2(N)lceil \左-1 \右\ rceil \)
ライン上の剪定を満たしていないサブツリーの深さを検索するときに覚えて、このような場合は、確かに唯一の深さを検索する(\左\ lceilのLOG2は、(Nは )\右rceil \ \)\ 内に、生きることができます。

コード

使用するには、Freopen

#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=17;
int N,M,A[MAXN][MAXN];
int vis[MAXN],Q[MAXN],Len;
int Cnt[1<<MAXN],H[MAXN];
vector<int>P[MAXN];
long long Dp[1<<(MAXN-1)][MAXN][MAXN>>1];
int lowbit(int x){return x&(-x);}
long long DFS(int S,int rt,int dep){
    if(Dp[S][rt][dep]!=-1)return Dp[S][rt][dep];
    long long &ret=(Dp[S][rt][dep]=0);
    if(Cnt[S]==1){
        if(S&(1<<(rt-1)))return ret=1;
        return ret=0;
    }
    for(int x=S&(S-1);x;x=S&(x-1)){//其实对于枚举子集可以优化.
        int y=S-x;
        if(!(x&(1<<(rt-1))))continue;
        if(H[Cnt[x]]>dep-1)continue;
        if(H[Cnt[y]]>dep-1)continue;
        long long Ans1=0,Ans2=0;
        Ans1=DFS(x,rt,dep-1);
        int size=P[rt].size();
        for(int i=0;i<size;i++){
            int v=P[rt][i];
            if(!(y&(1<<(v-1))))continue;
            Ans2+=DFS(y,v,dep-1);
        }
        ret+=Ans1*Ans2;
    }
    return ret;
}
int main(){
    //freopen("f.in","r",stdin);
    //freopen("f.out","w",stdout);
    scanf("%d%d",&N,&M);
    for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++){
            scanf("%d",&A[i][j]);
            if(A[i][j])P[i].push_back(j);
        }
    for(int i=1;i<=N;i++)H[i]=ceil(log2(i));
    for(int i=1;i<(1<<N);i++)
        Cnt[i]=Cnt[i>>1]+(i&1);
    memset(Dp,-1,sizeof(Dp));
    printf("%lld\n",DFS((1<<N)-1,M,H[N]));
}

おすすめ

転載: www.cnblogs.com/ftotl/p/11839637.html