一些关于状压dp的题目

有些题目打得比较幼稚。。。
贴这些主要是收集状压Dp

jzoj 1340周长:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace std;
int f[32768][16],a[21];
long long fa[32768][16];
int main()
{
    int n;
    int p=0,t=0;
    scanf("%d",&n);
    int two[17]{0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        f[two[i]][i]=a[i]+2;
        fa[two[i]][i]=1;
    }
    int m=two[n+1]-1;
    long long ans=-2147483647;
    long long sum=0;
    for (int i=1;i<=m;i++)
    {
        for (int j=1;j<=n;j++)
        {
            if ((i & two[j])!=0)
                for (int k=1;k<=n;k++)
                if (( two[k] & i)==0)
                {
                    p=i+two[k];
                    t=f[i][j]+2+abs(a[k]-a[j]);
                    if (t==f[p][k]) fa[p][k]=fa[i][j]+fa[p][k];
                    else if (t>f[p][k]) 
                    {
                        f[p][k]=t;
                        fa[p][k]=fa[i][j];
                    }
                }
            if (ans==f[i][j]+a[j]) sum+=fa[i][j];
            else if (ans<(f[i][j]+a[j]))
            {
                ans=f[i][j]+a[j];
                sum=fa[i][j];
            }
        }
    }
    printf("%lld %lld",ans,sum);
}

jzoj 1768. 【NOI2001】炮兵阵地【难】

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#define N 200
#define fo(i,a,b) for (int i=a;i<=b;i++)
using namespace std;
int n,m,G[N],b[N],F[N][N][N],sum[N],tot=0;
char ch;
bool pd(int x)
{
    if (x&(x<<1)) return false;
    if (x&(x<<2)) return false;
    return true;
}
int GetSum(int x)
{
    int S=0;
    while (x)
    {
        if (x&1) S++;
        x>>=1;
    }
    return S;
}
int main()
{
    freopen("data10.in","r",stdin);
    scanf("%d%d",&n,&m);
    fo(i,1,n) 
        fo(j,1,m)
        {
            cin>>ch;
            if (ch=='H') G[i]+=1<<(j-1);
        }   
    int p=(1<<m)-1;
    tot=0;
    fo(i,0,p)
        if (pd(i))
        {
            b[++tot]=i;
            sum[tot]=GetSum(i);
        }

    memset(F,255,sizeof(F));
    fo(i,1,tot)
    if (!(G[1]&b[i])) F[1][1][i]=sum[i];

    fo(i,1,n)
        fo(j,1,tot)
        if (!(G[i]&b[j]))
            fo(k,1,tot)
            if (!(b[j]&b[k]))
            {
                fo(l,1,tot) 
                if (!(b[j]&b[l]))
                {
                    int q=F[i-1][l][k]+sum[j];
                    if (F[i-1][l][k]!=-1) F[i][k][j]=max(F[i][k][j],q);
                }
            }
    int ans=0;
    fo(i,1,tot) 
        fo(j,1,tot) ans=max(ans,F[n][i][j]);
    printf("%d",ans);
}

另一种写法



#include<cstdio>  
int max(int a,int b){return a>b?a:b;}  
int dp[100][100][100];  
int st[100];//每种状态的二进制数  
int sum[100];//每种状态的炮塔数  
int col[100];//按列存放每一行1(指高地)的分布  
int cnt;//合法状态总数  
char s[10];  
bool J(int x){//判断状态是否合法(每两个1中间至少有2个0)  
    if(x&(x<<1))return 0;  
    if(x&(x<<2))return 0;  
    return 1;  
}  
int getSum(int x){//获得状态x下所安置的炮塔数(即求x有多少个二进制位1)  
    int res=0;  
    while(x){  
        if(x&1)res++;  
        x>>=1;  
    }  
    return res;  
}  
void pre(int m){//预处理出所有合法状态及该状态下炮塔数  
    int i,e=1<<m;  
    cnt=0;  
    for(i=0;i<e;i++)
    {  
        if(J(i))st[cnt]=i,sum[cnt++]=getSum(i);  
    }  
}  
void clear(int x){  
    for(int i=0;i<cnt;i++)for(int j=0;j<cnt;j++)dp[x][i][j]=-1;  
}  
int main(){  
    freopen("data10.in","r",stdin);
    int n,m,i,j,r1,r2;  
    while(~scanf("%d%d",&n,&m)){  
        pre(m);  
        for(i=0;i<n;i++)col[i]=0;  
        for(i=0;i<n;i++){  
            scanf("%s",s);  
            for(j=0;j<m;j++)if(s[j]=='H')col[i]|=(1<<j);  
        }  
        for(i=0;i<n;i++)clear(i);  
        for(i=0;i<cnt;i++)if(!(col[0]&st[i]))dp[0][0][i]=sum[i];//第0行  
        for(i=1;i<n;i++){  
            for(j=0;j<cnt;j++)if(!(col[i]&st[j])){//当前行状态(高地与当前状态不冲突)  
                for(r1=0;r1<cnt;r1++)if(!(st[j]&st[r1])){//前一行状态(与当前状态不冲突)  
                    for(r2=0;r2<cnt;r2++)if(!(st[j]&st[r2])){//前二行状态(与当前状态不冲突)  
                        if(dp[i-1][r2][r1]!=-1)dp[i][r1][j]=max(dp[i][r1][j],dp[i-1][r2][r1]+sum[j]);  
                    }  
                }  
            }  
        }  
        int ans=0;  
        for(i=0;i<cnt;i++)for(j=0;j<cnt;j++)ans=max(ans,dp[n-1][i][j]);  
        printf("%d\n",ans);  
    }  
    return 0;  
}  

jzoj 1389. 玩诈欺的小杉【推荐】

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for (int i=a;i<=b;i++) 
using namespace std;
char c;
int n,m,T;
int F[30],ans=0,p,now,x,Temp,Before;
void Work(int x)
{
    now=x;Before=0;
    fo(i,1,m)
    {
        Temp=now;
        now=((now>>1)^(now>>2)^(now<<1)^(now<<2)^Before^now^F[i])&p;
        Before=Temp;
    }
    if (!(now)) ans++;
}
int main()
{
    //freopen("1389.in","r",stdin);
    int T;
    scanf("%d%d%d",&n,&m,&T);
    while (T--)
    {
        memset(F,0,sizeof(F));
        ans=0;
        p=(1<<(n))-1;
        fo(i,1,n)
            fo(j,1,m)
            {
                c=getchar();
                while(c!='0' && c!='1')c=getchar();
                if (c=='1') F[j]=F[j]+(1<<(i-1));
            }
        fo(i,0,p) Work(i);
        printf("%d\n",ans);
    }
}

jzoj 1060. 五子棋

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#define N 15
using namespace std;
int a[N][N],b[N][N],c[N],f[N][8192];
int main()
{
    //freopen("data10.in","r",stdin);
    //freopen("data.out","w",stdout);
    int T,n,x;
    int two[15]{0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192};
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        memset(f,0,sizeof(f));
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
            scanf("%d",&b[i][j]);
        for (int i=1;i<=n;i++)
            scanf("%d",&c[i]);
        int m=two[n+1]-1;
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m;j++)
                for (int k=2;k<=n;k++)
                if (!(j&two[k]))
                {
                    int x=c[1];
                    for (int l=2;l<=n;l++)
                        if ((j&two[l])) x+=a[1][l];
                    int p=j+two[k];
                    if (x>c[k]) f[i+1][p]=max(f[i+1][p],f[i][j]+b[1][k]);
                    else f[i+1][p]=max(f[i+1][p],f[i][j]);
                }
        }
        printf("%d\n",f[n][m]);
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值