码迷,mamicode.com
首页 > 其他好文 > 详细

P1896 [SCOI2005]互不侵犯

时间:2019-01-26 21:37:09      阅读:133      评论:0      收藏:0      [点我收藏+]

标签:code   void   ret   name   print   nbsp   names   int   代码   

  我好久都没有发博客了……

  可不是因为我没做题啊,因为懒得发qwq……

  今天发一波状压dp(就是dp)。

  我还想不到如果不是格子图,状压dp怎么用……

  因为它与dp的不同就是它可以用二进制来表示这一位(这个格子选不选)……

  dp [ i ] [ j ] [ t ] 表示第 i 行,第 j 个状态,选择 t 个的方案数……

  其实因为每一行都一样,所以其实所谓状态 j 就是第 j 种放法罢了,而第几行其实无所谓,因为每一行都一样。

  当然一开始第1行,第 j 种状态,放第 j 种状态下应该放的数量的方案数自然是1。

  接下来上代码:

#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
int dp[20][200][200],mark[200],uni[200],ans[200],sta[200];
vector<int> sec[900];
int n,k,tot;
void dfs(int x)
{
    if(x==n+1)
    {
        tot++;
        for(int i=1; i<=n; i++)
        {
            sta[tot]*=2;
            sta[tot]+=ans[i];
            mark[tot]+=ans[i];
        }
        return ;
    }
    ans[x]=0;
    dfs(x+1);
    if(!ans[x-1])
    {
        ans[x]=1;
        dfs(x+1);
        ans[x]=0;
    }
}
bool ac(int l1,int l2)
{
    for (int i = 2; i < n; i++)
    {
        if ((sta[l1] & uni[i]) && ((sta[l2] & uni[i - 1]) || (sta[l2] & uni[i]) || (sta[l2] & uni[i + 1])))
            return 0;
        if ((sta[l2] & uni[i]) && ((sta[l1] & uni[i - 1]) || (sta[l1] & uni[i]) || (sta[l1] & uni[i + 1])))
            return 0;
    }
    if( (sta[l1] & uni[1]) && ( (sta[l2] & uni[1]) || sta[l2] & uni[2] ) ) return 0;
    if( (sta[l1] & uni[n]) && ( (sta[l2] & uni[n]) || sta[l2] & uni[n-1]) ) return 0;
    if( (sta[l2] & uni[1]) && ( (sta[l1] & uni[1]) || sta[l1] & uni[2] ) ) return 0;
    if( (sta[l2] & uni[n]) && ( (sta[l1] & uni[n]) || sta[l1] & uni[n-1]) ) return 0;
    return 1;
}
main()
{
    scanf("%lld%lld",&n,&k);
    if(n==0)
    {
        printf("0");
        return 0;
    }
    if(n==1)
    {
        if(k==0) printf("1");
        else printf("0");
        return 0;
    }
    uni[n]=1;
    for(int i=n-1; i>=1; i--)
        uni[i]=uni[i+1]<<1;
    dfs(1);
    for(int i=1; i<=tot; i++)
        for(int j=1; j<=tot; j++)
            if(ac(i,j)) sec[i].push_back(j);
    for(int i=0; i<=tot; i++)
        dp[1][i][mark[i]]=1;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=tot; j++)
            for(int t=mark[j]; t<=k; t++)
                for(int o=0; o<sec[j].size(); o++)
                {
                    dp[i][j][t]+=dp[i-1][sec[j][o]][t-mark[j]];
                }
    int sum=0;
    for(int i=1; i<=tot; i++)
        sum+=dp[n][i][k];
    printf("%lld",sum);
    return 0;

}

 

P1896 [SCOI2005]互不侵犯

标签:code   void   ret   name   print   nbsp   names   int   代码   

原文地址:https://www.cnblogs.com/popo-black-cat/p/10324894.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!