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; }

浙公网安备 33010602011771号