状态dp若干入门题

 1. hdu 1565 方格取数(1)

状态dp

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
int legal[1<<20];
int num,a[21][21];
int dp[21][1<<20];
int n;
void init()
{
    num=0;
    for(int i=0;i<(1<<n);i++)
    {
        if(i&(i<<1) || i&(i>>1))
            continue;
        legal[++num]=i;
    }
}
int get(int i,int j) // 第i行第j种状态下,本行可获取的值
{
    int ans=0;
    int tmp=legal[j];
    int k=n;
    while(tmp)
    {
        if(tmp&1)
            ans+=a[i][k];
        k--;
        tmp/=2;
    }
    return ans;
}
int main()
{
    init();
    while(scanf("%d",&n)!=EOF)
    {
        init();
        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++)
            a[0][i]=0;
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=num;j++)
            {
                int tmp=-0xfffffff;
                for(int k=1;k<=num;k++)
                {
                    if(legal[j]&legal[k])
                        continue;
                    tmp=max(tmp,dp[i-1][k]);
                }
                dp[i][j]=tmp+get(i,j);
                ans=max(ans,dp[i][j]);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


2. poj 3254 Corn Fields

状态dp

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int mod=(1e8);
int dp[13][1<<12];
int legal[1<<12];
int num,pos[13];
int m,n;
void init()
{
    num=0;
    for(int i=0;i<(1<<n);i++)
    {
        if(i&(i<<1) || i&(i>>1))
            continue;
        legal[++num]=i;
    }
}
int main()
{
    int x;
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        init();
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;i++)
        {
            pos[i]=0;
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&x);
                if(x==0)
                    pos[i]|=1<<(n-j);
            }
        }
        for(int i=1;i<=num;i++)
        {
            if(legal[i]&pos[1])
                continue;
            dp[1][i]=1;
        }
        for(int i=2;i<=m;i++)
            for(int j=1;j<=num;j++)
            {
                if(pos[i]&legal[j])
                    continue;
                for(int k=1;k<=num;k++)
                {
                    if(pos[i-1]&legal[k])
                        continue;
                    if(legal[j]&legal[k])
                        continue;
                    dp[i][j]+=dp[i-1][k];
                    dp[i][j]%=mod;
                }
            }
        int ans=0;
        for(int i=1;i<=num;i++)
            ans=(ans+dp[m][i])%mod;
        printf("%d\n",ans);
    }
    return 0;
}


3. poj 1185 炮兵阵地

状态dp

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int legal[61];
int dp[101][61][61];
int pos[101];
int a[101][11];
int num,n,m;
void init()
{
    num=0;
    for(int i=0;i<(1<<m);i++)
        if( i&(i<<1) || i&(i<<2) || i&(i>>1) || i&(i>>2))
            continue;
        else
            legal[++num]=i;
}
int get(int i,int j)
{
    int ans=0;
    int tmp=legal[j];
    int k=m;
    while(tmp)
    {
        if(tmp&1)
            ans+=a[i][k];
        k--;
        tmp/=2;
    }
    return ans;
}
int main()
{
    char s;
    scanf("%d%d",&n,&m);
    getchar();
    init();
    memset(a,0,sizeof(a));
    memset(dp[1],0,sizeof(dp[1]));
    for(int i=1;i<=n;i++)
    {
        pos[i]=0;
        for(int j=1;j<=m;j++)
        {
            scanf("%c",&s);
            if(s=='H')
            {
                pos[i]|=1<<(m-j);
            }
            else
                a[i][j]=1;
        }
        getchar();
    }
    int ans=0;
    /// dp[i][j][k] 表示当前第i行状态为j,第i-1行状态为k的方案数
    //预处理第一行
    for(int i=1;i<=num;i++)
    {
        if(pos[1]&legal[i])
            continue;
        dp[1][i][1]=get(1,i);
        ans=max(ans,dp[1][i][1]);
    }
    // 预处理第二行
    for(int i=1;i<=num;i++)
    {
        if(pos[2]&legal[i])
            continue;
        for(int j=1;j<=num;j++)
        {
            if(pos[1]&legal[j])
                continue;
            if(legal[i]&legal[j])
                continue;
            dp[2][i][j]=dp[1][j][1]+get(2,i);
            ans=max(ans,dp[2][i][j]);
        }
    }
    for(int i=3;i<=n;i++)
    {
        for(int j=1;j<=num;j++) // 当前行的状态
        {
            if(pos[i]&legal[j])
                continue;
            for(int k=1;k<=num;k++) // 前一行的状态
            {
                if(legal[j]&legal[k])
                    continue;
                if(pos[i-1]&legal[k])
                    continue;
                int tmp=-1;
                for(int l=1;l<=num;l++)
                {
                    if(legal[l]&pos[i-2])
                        continue;
                    if(legal[l]&legal[k])
                        continue;
                    if(legal[l]&legal[j])
                        continue;
                    tmp=max(tmp,dp[i-1][k][l]);
                }
                dp[i][j][k]=tmp+get(i,j);
                ans=max(ans,dp[i][j][k]);
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}




4.light oj 1244 - Tiles

状态压缩,矩阵加速

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
#define mod 10007
struct Matrix
{
    long long m[5][5];
}E,D,T;
void init()
{
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            E.m[i][j]=(i==j);
            D.m[i][j]=0;
        }
    for(int i=1;i<=4;i++)
        D.m[1][i]=1;
    D.m[2][1]=1;
    D.m[3][2]=D.m[3][4]=1;
    D.m[4][2]=D.m[4][3]=1;
    T.m[1][1]=T.m[2][1]=1;
    T.m[3][1]=T.m[4][1]=0;
}
Matrix Multi(Matrix A,Matrix B)
{
    Matrix ans;
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            ans.m[i][j]=0;
            for(int k=1;k<=4;k++)
                ans.m[i][j]=(ans.m[i][j]+A.m[i][k]*B.m[k][j])%mod;
        }
    return ans;
}
Matrix Pow(Matrix A,long long k)
{
    Matrix ans=E;
    while(k)
    {
        if(k&1)
        {
            k--;
            ans=Multi(ans,A);
        }
        else
        {
            k/=2;
            A=Multi(A,A);
        }
    }
    return ans;
}
int main()
{
    int t;
    long long n;
    scanf("%d",&t);
    init();
    for(int cases=1;cases<=t;cases++)
    {
        scanf("%lld",&n);
        Matrix ans=Pow(D,n-1);
        ans=Multi(ans,T);
        printf("Case %d: %lld\n",cases,ans.m[1][1]);
    }
    return 0;
}



5. Tri Tiling

状态dp

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
long long dp[31][8];
int main()
{
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=1;i<=30;i++)
    {
        dp[i][0]=dp[i-1][1]+dp[i-1][4]+dp[i-1][7];
        dp[i][1]=dp[i-1][6]+dp[i-1][0];
        dp[i][2]=dp[i-1][5];
        dp[i][3]=dp[i-1][4];
        dp[i][4]=dp[i-1][0]+dp[i-1][3];
        dp[i][5]=dp[i-1][2];
        dp[i][6]=dp[i-1][1];
        dp[i][7]=dp[i-1][0];
    }
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n<0)
            break;
        printf("%lld\n",dp[n][0]);
    }
    return 0;
}



6. poj 2411 Mondriaan's Dream

棋盘覆盖

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
LL dp[12][1<<11];
// 设横着放的为11,竖着放的01
// 那么对于每行,一定不存在连续奇数的1
// 每两行不存在竖行连续为00
int m,n,mx;
bool ok1(int i)
{
    //
    int bits=0;
    while(i)
    {
        if(i&1)
            bits++;
        else
        {
            if(bits&1)
                return false;
            bits=0;
        }
        i/=2;
    }
    if(bits&1)
        return false;
    return true;
}
bool ok2(int a,int b)
{
    if((a|b)!=mx)
        return false;
    return ok1(a&b);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(m==n&&m==0)
            break;
        if((m*n)&1)
            printf("0\n");
        else
        {
            if(m<n)
                swap(m,n);
            mx=(1<<m)-1;
            memset(dp,0,sizeof(dp));
            for(int i=0;i<(1<<m);i++)
                if(ok1(i))
                    dp[1][i]=1;
            for(int i=2;i<=n;i++)
                for(int j=0;j<(1<<m);j++)
                    for(int k=0;k<(1<<m);k++)
                        if(ok2(j,k))
                            dp[i][j]+=dp[i-1][k];
            printf("%I64d\n",dp[n][(1<<m)-1]);
        }
    }
    return 0;
}


7. hdu 4539 郑厂长系列故事——排兵布阵

跟炮兵阵地一样,为了节省内存,用了滚动数组(上次看小萌用了这个)。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
int legal[170];
int dp[2][170][170];
int a[101][11];
int num,n,m;
int pos[101];
void init()
{
    num=0;
    for(int i=0;i<(1<<m);i++)
    {
        if(i&(i<<2) || i&(i>>2))
            continue;
        legal[++num]=i;
    }
}
int get(int i,int j)
{
    int tmp=legal[j];
    int k=m;
    int ans=0;
    while(tmp)
    {
        if(tmp&1)
        {
            ans+=a[i][k];
        }
        k--;
        tmp/=2;
    }
    return ans;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        memset(a,0,sizeof(a));
        //cout<<num<<endl;
        for(int i=1;i<=n;i++)
        {
            pos[i]=0;
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&a[i][j]);
                if(a[i][j]==0)
                    pos[i]|=(1<<(m-j));
            }
            //cout<<pos[i]<<endl;
        }
        int ans=0;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=num;i++)
        {
            if(pos[1]&legal[i])
                continue;
            dp[1][i][1]=get(1,i);
            ans=max(ans,dp[1][i][1]);
        }
        memcpy(dp[0],dp[1],sizeof(dp[1]));
        memset(dp[1],0,sizeof(dp[1]));
        for(int i=1;i<=num;i++)
        {
            if(pos[2]&legal[i])
                continue;
            for(int j=1;j<=num;j++)
            {
                if(pos[1]&legal[j])
                    continue;
                if((legal[j]<<1)&legal[i] || (legal[i]<<1)&legal[j])
                    continue;
                dp[1][i][j]=dp[0][j][1]+get(2,i);
                ans=max(ans,dp[1][i][j]);
            }
        }
        for(int i=3;i<=n;i++)
        {
            memcpy(dp[0],dp[1],sizeof(dp[0]));
            memset(dp[1],0,sizeof(dp[1]));
            for(int j=1;j<=num;j++)
            {
                if(pos[i]&legal[j])
                    continue;
                for(int k=1;k<=num;k++)
                {
                    if(legal[k]&pos[i-1])
                        continue;
                    if((legal[j]<<1)&legal[k] || (legal[k]<<1)&legal[j])
                        continue;
                    int tmp=-1;
                    for(int l=1;l<=num;l++)
                    {
                        if(legal[l]&pos[i-2])
                            continue;
                        if(legal[l]&legal[j])
                            continue;
                        if((legal[l]<<1)&legal[k] || (legal[k]<<1)&legal[l])
                            continue;
                        tmp=max(tmp,dp[0][k][l]);
                    }
                    dp[1][j][k]=tmp+get(i,j);
                    ans=max(ans,dp[1][j][k]);
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


8. nyoj 492 King

状态dp

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
int legal[150];
long long dp[2][150][101];
int num;
int n,k;
void init()
{
    num=0;
    for(int i=0;i<(1<<n);i++)
    {
        if(i&(i<<1) || i&(i>>1))
            continue;
        legal[++num]=i;
    }
}
int get(int i)
{
    int tmp=legal[i];
    int ans=0;
    while(tmp)
    {
        if(tmp&1)
            ans++;
        tmp/=2;
    }
    return ans;
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        init();
        //cout<<num<<endl;
        memset(dp,0,sizeof(dp));
        dp[1][1][0]=1;
        for(int i=1;i<=n;i++)
        {
            memcpy(dp[0],dp[1],sizeof(dp[0]));
            memset(dp[1],0,sizeof(dp[1]));
            for(int j=1;j<=num;j++)
            {
                for(int l=get(j);l<=k;l++)
                {
                    for(int p=1;p<=num;p++)
                    {
                        if(legal[p]&legal[j])
                            continue;
                        if((legal[p]<<1)&legal[j])
                            continue;
                        if((legal[p]>>1)&legal[j])
                            continue;
                        dp[1][j][l]+=dp[0][p][l-get(j)];
                    }
                }
            }
        }
        long long ans=0;
        for(int i=1;i<=num;i++)
            ans+=dp[1][i][k];
        printf("%lld\n",ans);
    }
    return 0;
}


9. poj 3311 Hie with the Pie

floyd + 状态dp

#include <cstdio>  
#include <cstring>  
#include <iostream>  
#include <cmath>  
#include <algorithm>  
using namespace std;  
int dp[1<<11][12];  
int cnt[12][12];  
int main()  
{  
    int n;  
    while(scanf("%d",&n),n!=0)  
    {  
        for(int i=0;i<=n;i++)  
            for(int j=0;j<=n;j++)  
                scanf("%d",&cnt[i][j]);  
        for(int k=0;k<=n;k++)
            for(int i=0;i<=n;i++)  
                for(int j=0;j<=n;j++)  
                    cnt[i][j]=min(cnt[i][j],cnt[i][k]+cnt[k][j]);  
        memset(dp,0x3f,sizeof(dp));  
        int ans=dp[0][0];  
        for(int state=0;state<(1<<n);state++)  
        {  
            for(int i=1;i<=n;i++)  
            {  
                if(state&(1<<(i-1)))  
                {  
                    if(state==(1<<(i-1)))  
                    {  
                        dp[state][i]=cnt[0][i];  
                        continue;  
                    }  
                    for(int j=1;j<=n;j++)  
                    {  
                        if(i==j)  
                            continue;  
                        if((1<<(j-1))&state)  
                            dp[state][i]=min(dp[state][i],dp[state&~(1<<(i-1))][j]+cnt[j][i]);  
                    }  
                }  
            }  
        }  
        for(int i=1;i<=n;i++)  
            ans=min(ans,dp[(1<<n)-1][i]+cnt[i][0]);  
        printf("%d\n",ans);  
    }  
    return 0;  
}  



或者用全排列水过

#include <cstdio>  
#include <cstring>  
#include <iostream>  
#include <cmath>  
#include <algorithm>  
using namespace std;  
int cnt[12][12];  
int path[12];  
int main()  
{  
    int n;  
    while(scanf("%d",&n),n!=0)  
    {  
        for(int i=0;i<=n;i++)  
            for(int j=0;j<=n;j++)  
                scanf("%d",&cnt[i][j]);  
        for(int k=0;k<=n;k++)
            for(int i=0;i<=n;i++)  
                for(int j=0;j<=n;j++)  
                    cnt[i][j]=min(cnt[i][j],cnt[i][k]+cnt[k][j]);  
        for(int i=1;i<=n;i++)  
            path[i]=i;  
        int ans=0x7fffffff;  
        int tmp;  
        do  
        {  
            tmp=cnt[0][path[1]];  
            tmp+=cnt[path[n]][0];  
            for(int i=1;i<n;i++)  
                tmp+=cnt[path[i]][path[i+1]];  
            ans=min(ans,tmp);  
  
        }while(next_permutation(path+1,path+n+1));  
        printf("%d\n",ans);  
    }  
    return 0;  
}  




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值