状压dp

完全不会
先抄一遍代码感受一下
1087: [SCOI2005]互不侵犯King
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 3860 Solved: 2261
[Submit][Status][Discuss]
Description

  在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。
Input

  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output

  方案数。
Sample Input
3 2
Sample Output
16
据说很水啊
不过我连八皇后还是最近才会的

#include<bits/stdc++.h>
using namespace std;
int n,m,all,cnt[512];
long long f[10][100][512];
bool c1[512],c2[512][512];
long long ans;
void pre()
{
    int s;//猜测目的应该是要去掉一些显然不成立的情况
    //例如两个国王在一起之类的 
    for(int i=0;i<=all;i++)
        if((i&(i>>1))==0)
        {
            s=0;
            for(int x=i;x;x>>=1) s+=(x&1);
            //判断国王的个数 
            cnt[i]=s;

            c1[i]=1;//定义这个情况是合理的 

        }
        for(int i=0;i<=all;i++)if(c1[i])
            for(int j=0;j<=all;j++) if(c1[j])
                if(((i&j)==0)&&((i&(j>>1))==0)&&((j&(i>>1))==0))
                    c2[i][j]=1;
                    //判断两种情况是否能和并
                    //首先两种情况都需要合法,如果两列不在同一个位置有点,且左右移也没有
                    //那么这两种情况就可以放在一起 
}

int main()
{
    scanf("%d%d",&n,&m);
    all=(1<<n)-1;//一串长度为n的1 
    pre(); 
    for(int i=0;i<=all;i++) if(c1[i]) f[1][cnt[i]][i]=1;//对于每种单个的情况 计数 
    for(int j=1;j<n;j++)//对于多个的情况计数 
        for(int k=0;k<=all;k++) if(c1[k])
            for(int i=0;i<=all;i++)if(c1[i])
                if(c2[k][i])
                    for(int p=cnt[k];p+cnt[i]<=m;p++)
                        f[j+1][p+cnt[i]][i]+=f[j][p][k];
                        //之后只要两行各自合法且合并合法就转移

    long long ans=0;

    for(int i=0;i<=all;i++) ans+=f[n][m][i];//将符合要求的情况加起来 
    printf("%lld",ans);
    return 0;
}

仔细标上注释发现其实蛮简单的
代码是抄的黄学长的。

所以可能需要强迫自己去跟着过程走一遍
注意要按程序运行顺序

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章