SGU 223

题目大意:给出一张n*n的棋盘和k个王,问有多少种使得王互不相攻击的方案。

题解:状压dp,设dp[i][j][S]表示前i行用了j个王,其中第i行放王的状态是S。

显然有dp[i][j][S]+=dp[i][j-cnt[S]][S'],其中cnt数组保存每个状态王的个数,且S'作为当前行可以在下一行放S这个状态。

位运算写错了妈了个鸡,还有用vector里的元素时直接用的指针,就这两个地方,第一次交WAontest 30,第二次A了。

%%%__debug大神,感谢Dash。

#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
const int MAXN=11,MAXK=101,MAXS=1025;
int n,k;
long long dp[MAXN][MAXK][MAXS];
int cnt[MAXS];
vector<int> s[MAXS];
bool vis[MAXS][MAXS];
void get1(int x)
{
    if(x==16)
       x=16;
    int tmp=x;
    while(tmp)
    {
        if(tmp&1)cnt[x]++;
        tmp>>=1;
    }
}
void dfs(int from,int x,int now)
{
    if(!vis[from][now])s[from].push_back(now),vis[from][now]=1;
    if(!(x^((1<<n)-1)))return;
    int tmp=x,cnt=0,check=x;
    while(cnt<n)
    {
        if(!(tmp&1))
        {
            if(cnt>0)check|=(1<<cnt-1);
            if(cnt<n-1)check|=(1<<cnt+1);
            check|=(1<<cnt);
            now|=(1<<cnt);
            dfs(from,check,now);
            check=x;
            now&=((1<<(10+1))-1)^(1<<cnt);
        }
        cnt++;
        tmp>>=1;
    }
}
void getSuf(int x)
{
    int tmp=x,cnt=0,check=0;
    while(cnt<n)
    {
        if(x&1)
        {
            if(cnt>0)check|=(1<<cnt-1);
            if(cnt<n-1)check|=(1<<cnt+1);
            check|=(1<<cnt);
        }
        cnt++;
        x>>=1;
    } 
    dfs(tmp,check,0);
}
void debug(int i)
{
    cout<<i<<' ';
    for(int j=0;j<s[i].size();j++)
            cout<<s[i][j]<<' ';
    cout<<endl;
}
int main()
{
    freopen("223.in","r",stdin);
    freopen("223.out","w",stdout);
    scanf("%d %d",&n,&k);
    long long ans=0;
    for(int i=0;i<(1<<n);i++)get1(i);
    for(int i=0;i<(1<<n);i++)
    {
        if(i&(i<<1))continue;
        getSuf(i);
        //debug(i);
    }
    dp[0][0][0]=1;
    for(int i=1;i<=n;i++)
       for(int j=0;j<=k;j++)
          for(int l=0;l<(1<<n);l++)
                for(int o=0;o<s[l].size();o++)
                    if(j-cnt[s[l][o]]>=0)
                        dp[i][j][s[l][o]]+=dp[i-1][j-cnt[s[l][o]]][l];//s[l][o] instead of o,o is just a pointer!
    for(int i=0;i<(1<<n);i++)ans+=dp[n][k][i];
    cout<<ans<<endl;
}

你可能感兴趣的:(sgu)