SCOI2005互不侵犯(状压dp)

src:https://www.luogu.org/problemnew/show/P1896

 这里的dp[i][j][k]表第i行为j状态用了k个king(注意:这里的j指的是第j个状态,不是一个二进制数,开一个数组state[]保存二进制状态) 

ac代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
#include <cstdlib>
#include<malloc.h>
#include<algorithm>
#include<functional>
#include<utility>
#include<cmath>
#include<string.h>
#include<string>
#include<vector>
#include<stack>
#include<set>
#include<queue>
#include<list>
//#include<bits/stdc++.h>
using namespace std;
int Max(int a, int b) { return a > b ? a : b; }
int Min(int a, int b) { return a > b ? b : a; }
#define FOR(i,a,b) for(int i=a;i<=b;i++)
typedef long long LL;
typedef unsigned long long ull;
const double INF = 99999999999.0;
const double eps = 1e-6;
int n,k;
long long dp[10][1024][85],king[1000],state[1024],nlegal,ans,tot;
//king表某状态下king的数量~~~state为合法状态
void init()
{
    nlegal=ans=0;
    tot=(1<<n)-1;//哇,要注意优先级啊!!!
    memset(king,0,sizeof(king));
    FOR(i,0,tot){
        if(!((i<<1)&i)){
            state[++nlegal]=i;
            int tmp=i;
            while(tmp){
                king[nlegal]+=tmp%2;tmp>>=1;
            }
        }
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin>>n>>k;
    init();
    for(int i=1;i<=nlegal;i++){//初始化
        if(king[i]<=k)dp[1][i][king[i]]=1;
    }
    for(int i=2;i<=n;i++){
        for(int j=1;j<=nlegal;j++){//给第i行选择状态!
            for(int p=1;p<=nlegal;p++){//给第i-1行选择状态!
                if(state[j]&state[p])continue;
                if(state[j]&(state[p]<<1))continue;
                if((state[j]<<1)&state[p])continue;
                for(int t=0;t<=k;t++){
                    if(king[j]+t>k)continue;
                    dp[i][j][king[j]+t]+=dp[i-1][p][t];
                }
            }
        }
    }
    //i个阶段,后面两个状态要求的是king必须为k,而第n行的状态随意,故扫描j !!!
    FOR(j,1,nlegal)ans+=dp[n][j][k];
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2018-04-05 23:14  WindFreedom  阅读(246)  评论(0)    收藏  举报