【codevs2451】互不侵犯

今天心情--,连续两次失利

作为今天考试的t2,浪费了太多时间,还没有做出正解

考完试反思,虽然这是第一次在考场上做状压dp,但是这个题并非不可做,而且部分分也很多

从这个题看出,状压有点时候会需要预处理处所有状态

教训:先看一遍所有的题,先打暴力

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long lo;
lo n,k1,tot,dp[10][100][550],cnt[550],sy[550],ans;
bool mmp[110][110];
void dfs(lo k,lo wei,lo pos)
{
    cnt[++tot]=k,sy[tot]=pos;//新纪录一种答案 
    if(k>=(n+1)/2||k>=k1)//如果k这个值即将超过限定最多所放的棋子数,或者这行棋子数超过(n+1)/2 ,也就是说有的棋子挨着 
        return;//即返回 
    for(int i=wei+2;i<=n;i++)//枚举下一个棋子位置,至少要给棋子之间留一个空 
        dfs(k+1,i,pos+(1<<(i-1)));
}
inline void yu()
{
    dfs(0,-1,0);//深搜预处理状态 
    for(int i=1;i<=tot;i++)//枚举状态,判断是否可以挨着 
        for(int j=i;j<=tot;j++)
            mmp[i][j]=mmp[j][i]=((sy[i]&sy[j])||(sy[i]<<1)&sy[j]||(sy[i]>>1)&sy[j])?0:1;
    for(int i=1;i<=tot;i++)
        dp[1][cnt[i]][i]=1;//初始化 
}
int main()
{
    scanf("%lld%lld",&n,&k1);
    yu();//预处理 
    for(int i=2;i<=n;i++)//枚举行 
        for(int j=0;j<=k1;j++)//枚举放置棋子个数 
            for(int k=1;k<=tot;k++)//枚举现在这行状态 
            {
                if(cnt[k]>j)
                    continue;
                for(int l=1;l<=tot;l++)//枚举上一行的状态 
                    if(cnt[k]+cnt[l]<=j&&mmp[k][l])//如果这两行状态不重复且棋子数未超过限制 
                        dp[i][j][k]+=dp[i-1][j-cnt[k]][l];
            }
    for(int i=1;i<=tot;i++)
        ans+=dp[n][k1][i];//答案在最后一行所有的状态里 
    cout<<ans;
}

 

posted @ 2017-10-12 16:30  那一抹落日的橙  阅读(158)  评论(0编辑  收藏  举报