Mark一下, dp状态转移方程写对,但是写代码都错,poj 1651 poj 1179

dp题:

1、写状态转移方程;

2、考虑初始化边界,有意义的赋定值,还没计算的赋边界值;

3、怎么写代码自底向上计算最优值

今天做了几个基础dp,全部是dp方程写对但是初始化以及计算写错

先是poj 1651 其实就是个赤裸裸的矩阵连乘,dp方程很容易写出

dp[i][j]=min(dp[i][k]+dp[k+1][j]+r[i]*c[k]*c[j],dp[i][j]);

先贴两个个二逼的代码,mark下自己多么的二逼:

二逼一:在计算的时候使用了还没有算出来的值,模拟下就知道第一重循环里算dp[0][2]=dp[0][0]+dp[1][2];

!!!!!dp[1][2]这时候根本没有计算出来还,Tmd我就用了这个值!!!!!!!!!!!!!!!!!!!!!!!二逼啊!!!!!!!!!

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int SIZE = 100+10;
const int INF = 10000000;
int dp[SIZE][SIZE];
int r[SIZE],c[SIZE];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {

        for(int i=0;i<n-1;i++)
        {
            scanf("%d",&r[i]);
            if(i>0)c[i-1]=r[i];
        }
        scanf("%d",&c[n-2]);
        n--;
        int ans=0;
        for(int i=0;i<n;i++)dp[i][i]=0;

        for(int i=0;i<=n;i++)
            for(int j=i;j<n;j++)
            {

                for(int k=i;k<j;k++)
                    dp[i][j]=min(dp[i][k]+dp[k+1][j]+r[i]*c[k]*c[j],dp[i][j]);
            }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
                printf("%d ",dp[i][j]);
            putchar('\n');
        }

        printf("%d\n",dp[0][n-1]);

    }
    return 0;
}

二逼二:来回换思路的时候各种思路弄混,看注释

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int SIZE = 100+10;
const int INF = 10000000;
int dp[SIZE][SIZE];
int r[SIZE],c[SIZE];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {

        for(int i=0;i<n-1;i++)
        {
            scanf("%d",&r[i]);
            if(i>0)c[i-1]=r[i];
        }
        scanf("%d",&c[n-2]);
        n--;
        int ans=0;
        for(int i=0;i<n;i++)dp[i][i]=0;
        int j;
        for(int l=2;l<=n;l++)
            for(int i=0;i<l;i++)//此处i<l及其傻逼,请勿模仿
            {
                j=i+l-1;
                dp[i][j]=INF;
                for(int k=i;k<j;k++)
                    dp[i][j]=min(dp[i][k]+dp[k+1][j]+r[i]*c[k]*c[j],dp[i][j]);
            }
        /*for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
                printf("%d ",dp[i][j]);
            putchar('\n');
        }*/

        printf("%d\n",dp[0][n-1]);

    }
    return 0;
}

正确代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
#define ll long long
const int SIZE = 100+10;
const int INF = 200000000;
ll dp[SIZE][SIZE];
int r[SIZE],c[SIZE];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {

        for(int i=0;i<n-1;i++)
        {
            scanf("%d",&r[i]);
            if(i>0)c[i-1]=r[i];
        }
        scanf("%d",&c[n-2]);
        n--;
        int ans=0;
        for(int i=0;i<=n;i++)dp[i][i]=0;
        int j;
        for(int l=2;l<=n;l++)
            for(int i=0;i<n-l+1;i++)
            {
                j=i+l-1;
                dp[i][j]=INF;
                for(int k=i;k<j;k++)
                    dp[i][j]=min(dp[i][k]+dp[k+1][j]+r[i]*c[k]*c[j],dp[i][j]);
            }
        printf("%lld\n",dp[0][n-1]);

    }
    return 0;
}

在做这个poj 1651之前  先做的poj 1179,然后过了poj 1651之后改了poj1179原来的循环次序,其实就是类比这个poj1651,第一重循环弄成长度即可

注意 负数乘以负数是正数 考虑最大最小值得时候一定注意

不过重新检查下发现代码在初始化的时候冗余,精简了下。

贴代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
#define ll long long

const int SIZE =55;
const int INF =  (-2147483647 ) ;

ll dp[SIZE][SIZE],dpmin[SIZE][SIZE];
int pos[SIZE];
bool op[SIZE];

int main()
{
    //freopen("poj1179.txt","r",stdin);
    int n;
    ll tmp1,tmp2;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)dp[i][0]=dpmin[i][0]=0;
        for(int i=0;i<n;i++)
        {
            scanf(" %c %lld",&op[i],&dp[i][1]);
            dpmin[i][1]=dp[i][1];
        }
        for(int j=1;j<=n;j++)
            for(int i=0;i<n;i++)
            {
                if(j>1)dp[i][j]=INF,dpmin[i][j]=-INF;
                for(int k=1;k<j;k++)
                {
                    if(op[(i+k)%n ] == 't')
                    {
                        dp[i%n][j]=max(dp[i%n][k]+dp[(i+k)%n ][j-k],dp[i%n][j]);
                        dpmin[i%n][j]=min(dpmin[i%n][k]+dpmin[(i+k)%n ][j-k], dpmin[i%n][j]);
                    }

                    else
                    {
                        tmp1=max(dp[i%n][k]*dp[(i+k)%n ][j-k],dpmin[i%n][k]*dpmin[(i+k)%n ][j-k]);
                        tmp2=max(dp[i%n][k]*dpmin[(i+k)%n ][j-k], dpmin[i%n][k]*dp[(i+k)%n ][j-k]);
                        tmp1=max(tmp1,tmp2);
                        dp[i%n][j]=max(tmp1,dp[i%n][j]);
                        tmp2=min(dp[i%n][k]*dp[(i+k)%n ][j-k],dpmin[i%n][k]*dpmin[(i+k)%n ][j-k]);
                        tmp1=min(dp[i%n][k]*dpmin[(i+k)%n ][j-k], dpmin[i%n][k]*dp[(i+k)%n ][j-k]);
                        tmp2=min(tmp1,tmp2);
                        dpmin[i%n][j]=min(dpmin[i%n][j],tmp2);
                    }

                }
            }
        int cnt=0;
        ll ans=INF;
        for(int i=0;i<n;i++)//开始的时候,这里i<=n,于是初始化的时候必须优dp[n][...]=INF,才能AC,奇怪的是计算过程中第一个下标我都%n了,最后才看到这里的问题
        {
            ans=max(ans,dp[i][n]);
        }
        for(int i=0;i<n;i++)
            if(ans == dp[i][n])
                pos[cnt++]=i+1;

        printf("%lld\n",ans);
        for(int i=0;i<cnt;i++)
            if(i == cnt-1)printf("%d\n",pos[i]);
            else printf("%d ",pos[i]);
    }

    return 0;
}

Mark一下, dp状态转移方程写对,但是写代码都错,poj 1651 poj 1179

时间: 2024-10-26 02:51:23

Mark一下, dp状态转移方程写对,但是写代码都错,poj 1651 poj 1179的相关文章

DP问题各种模型的状态转移方程 (转)

1(最长公共子串(注意和最长公共子序列区别)) 两个字符串str1和str2,长度分别为(l1,l2) dp[i][j]表示以两个字符串分别以第i和第j个字符结尾所能达到的公共子序列的长度,由于下面涉及到i-1和j-1,那么这个时候我们一般从i=1和j=1开始到i<=len1, j<=len2. if(str[i-1]=str[j-1]) dp[i][j]=dp[i-1][j-1]+1; if(str[i-1]!=str[j-1]) dp[i][j]=0; 0 ;              

[转]DP问题各种模型的状态转移方程

1(最长公共子串(注意和最长公共子序列区别)) 两个字符串str1和str2,长度分别为(l1,l2) dp[i][j]表示以两个字符串分别以第i和第j个字符结尾所能达到的公共子序列的长度,由于下面涉及到i-1和j-1,那么这个时候我们一般从i=1和j=1开始到i<=len1, j<=len2. if(str[i-1]=str[j-1]) dp[i][j]=dp[i-1][j-1]+1; if(str[i-1]!=str[j-1]) dp[i][j]=0; 0 ;              

dp状态压缩

dp状态压缩 动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩的动态规划解决的就是那种状态很多,不容易用一般的方法表示的动态规划问题,这个就更加的难于把握了.难点在于以下几个方面:状态怎么压缩?压缩后怎么表示?怎么转移?是否具有最优子结构?是否满足后效性?涉及到一些位运算的操作,虽然比较抽象,但本质还是动态规划.找准动态规划几个方面的问题,深刻理解动态规划的原理,开动脑筋思考问题.这才是掌握动态规划的关键. 动态规划最关键的要处理的问题就是位运算的操作,容易出错,状态的设计也直

【转载】 HDU 动态规划46题【只提供思路与状态转移方程】

1.Robberies 连接 :http://acm.hdu.edu.cn/showproblem.php?pid=2955 背包;第一次做的时候把概率当做背包(放大100000倍化为整数):在此范围内最多能抢多少钱  最脑残的是把总的概率以为是抢N家银行的概率之和- 把状态转移方程写成了f[j]=max{f[j],f[j-q[i].v]+q[i].money}(f[j]表示在概率j之下能抢的大洋); 正确的方程是:f[j]=max(f[j],f[j-q[i].money]*q[i].v)  其

dp + 状态压缩 - Codeforces 580D Kefa and Dishes

Kefa and Dishes Problem's Link Mean: 菜单上有n道菜,需要点m道.每道菜的美味值为ai. 有k个规则,每个规则:在吃完第xi道菜后接着吃yi可以多获得vi的美味值. 问:最多可以获得多少美味值? (1≤m≤n≤18,0≤k≤n∗(n−1)) analyse: 经典的状压DP. 由于最多18道菜,可用一个数s(s<=2^18)来唯一标识一种状态. 对于一个状态s,枚举两个位置i和j:i从已选择的菜中选定,j从未选择的菜中选定. 下一个状态ss的就是:吃完i后接着

ACM学习历程—ZOJ3471 Most Powerful(dp &amp;&amp; 状态压缩 &amp;&amp; 记忆化搜索 &amp;&amp; 位运算)

Description Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These atoms have some properties. When two of these atoms collide, one of them disappears and a lot of power is produced. Researchers know the way

(review)zoj4800 二维dp 状态转移很灵活

1 #include<iostream> 2 #include<stdio.h> 3 4 using namespace std; 5 6 double dp[10005][125]; 7 double p[125][125]; 8 int pk[10005]; 9 10 int N,M; 11 12 double fmax(double a,double b){ 13 if(a-b>0) return a;else return b; 14 } 15 int main(){

HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)

题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由于得到每张卡片的状态不知道,所以用状态压缩,dp[i] 表示这个状态时,要全部收齐卡片的期望. 由于有可能是什么也没有,所以我们要特殊判断一下.然后就和剩下的就简单了. 另一个方法就是状态压缩+容斥,同样每个状态表示收集的状态,由于每张卡都是独立,所以,每个卡片的期望就是1.0/p,然后要做的就是要去重,既然

uva 11367 dijkstra+dp状态压缩

题意:给出n个地点 和 每个地点的油价 ,有 m 条边 , 并给出每条边长度 .1单位汽油可以走1千米  , 油箱的容量为 c , 在初始点 s 时 , 油箱中的油为 0 , 求s 到 t 的最小花费 . 解法: 定义 状态 d[i][j] 表示到达 地点 i 且油箱中有 j 单位油时的最小 花费. 对于状态的转移时 , 有两种方法: 1.把每个点的所有状态都求出 2.不把每个点的状态都求出 , 而是一单位一单位的加油. 对于第一种方法 , 会超时 , 因为每个点的状态太多 , 但是能用的状态就