现在的位置: 首页 > 综合 > 正文

插头DP(HDOJ1693)初识

2013年12月06日 ⁄ 综合 ⁄ 共 1324字 ⁄ 字号 评论关闭

看了看某PPT后,乱写了一下午~~

下面的代码写法上不是最优的,但能体现思路,合写了的话就会根本不知道怎么来的:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int N=12;
const int NN=1<<N;

int n,m,b,s[N][N];
long long dp[N][N][NN];

bool One(int x,int p)
{
    if (x&(1<<p)) return true;
    else          return false;
}

bool Zero(int x,int p)
{
    if (x&(1<<p)) return false;
    else          return true;
}

int main()
{
    int cases,casecnt=0;
    scanf("%d",&cases);
    while (cases--)
    {
        //input & init
        scanf("%d%d",&n,&m);
        for (int i=1; i<=n; i++)
            for (int j=1; j<=m; j++) scanf("%d",&s[i][j]);
        memset(dp,0,sizeof(dp));
        for (int j=0; j<=m; j++) dp[0][j][0]=1;
        b=(1<<(m+1))-1;
        
        //DP
        for (int i=1; i<=n; i++)
        {
            for (int k=0; k<=b>>1; k++)
                dp[i][0][k<<1] = dp[i-1][m][k];
                
            for (int j=1; j<=m; j++)
            {
                for (int k=0; k<=b; k++)
                {
                    if (s[i][j]==0) // (i,j)位置上没有树
                    {
                        if (Zero(k,j-1) && Zero(k,j))
                            dp[i][j][k] += dp[i][j-1][k];
                        continue;
                    }
                    if (Zero(k,j-1) && Zero(k,j))
                    {
                        dp[i][j][k^(3<<(j-1))] += dp[i][j-1][k]; // 六种路径方向,3:30(时钟位置)
                    }
                    if (Zero(k,j-1) && One(k,j))
                    {
                        dp[i][j][k] += dp[i][j-1][k]; // 3:00
                        dp[i][j][k^(3<<(j-1))] += dp[i][j-1][k]; // 6:00
                    }
                    if (One(k,j-1) && Zero(k,j))
                    {
                        dp[i][j][k] +=dp[i][j-1][k];   // 6:45
                        dp[i][j][k^(3<<(j-1))] += dp[i][j-1][k]; // 9:15
                    }
                    if (One(k,j-1) && One(k,j))
                    {
                        dp[i][j][k^(3<<(j-1))] += dp[i][j-1][k]; // 9:00
                    }
                }
            }
        }
        if (n==1 || m==1) dp[n][m][0]=0;
        printf("Case %d: There are %I64d ways to eat the trees.\n",++casecnt,dp[n][m][0]);
    }
    return 0;
}

这个DP思想重点(对于这题)在于考虑在整体之下的个体的根本规律,我们通过每格的应有姿态(回路中的点一进一出两个插头)来推算整体,又想到这种表达不难却很难想到的DP路径和状态,好厉害的说。继续学习。

抱歉!评论已关闭.