初学动态规划

本文探讨了两道动态规划问题的解决方案,包括Mr.Young's Picture Permutations问题,通过五行学生排列的动态规划计算,以及E-传纸条问题,利用状态转移求解两条路线的最大权值。文章深入解析了状态表示和状态计算的关键步骤,展示了如何通过递推公式找到最优解。
摘要由CSDN通过智能技术生成


A - Mr. Young’s Picture Permutations

传送门
在这里插入图片描述

#include <iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N=31;
#define ll long long
int main()
{
    int  n,i,j,k;
    int a,b,c,d,e;//分别代表第一行,第二行,。。。,第五行
    int s[5];
    while( cin>>n)
    {
        if(n==0)
            break;
        memset(s,0,sizeof s);
        for(i=0; i<=n-1; i++)
            cin>>s[i];
        ll f[s[0]+1][s[1]+1][s[2]+1][s[3]+1][s[4]+1];
        memset(f,0,sizeof(f));
        f[0][0][0][0][0]=1;
        //状态集合对应集合的划分,令最后一个同学安排在哪一排作为划分依据
        for(a=0; a<=s[0]; a++)
            for(b=0; b<=min(a,s[1]); b++)
                for(c=0; c<=min(b,s[2]); c++)
                    for(d=0; d<=min(c,s[3]); d++)
                        for(e=0; e<=min(d,s[4]); e++)
                        {
                            //& 完全引用
                            ll &x=f[a][b][c][d][e];//当前f[a][b][c][d][e].要由f[a-1][b][c][d][e]转移
                            //转移需满足两个要求。
                            //1、当前位置放下的数字要小于等于当前行要求放的数字的个数
                            //2、放下此人后,不能大于前一行放下的人的个数
                            //注意,(可能)第一行人数多,k行人数少
                            if(a&&a-1>=b)//最后一名同学可能被安排在第一排
                                x+=f[a-1][b][c][d][e];
                            if(b&&b-1>=c)//最后一名同学可能被安排在第二排
                                x+=f[a][b-1][c][d][e];
                            if(c&&c-1>=d)//最后一名同学可能被安排在第三排
                                x+=f[a][b][c-1][d][e];
                            if(d&&d-1>=e)//最后一名同学可能被安排在第四排
                                x+=f[a][b][c][d-1][e];
                            if(e)//最后一名同学可能被安排在第五排
                                x+=f[a][b][c][d][e-1];
                        }
        cout<<f[s[0]][s[1]][s[2]][s[3]][s[4]]<<endl;
    }
    return 0;
}

E - 传纸条

传送门

状态表示

f(x1,x2)

集合:所有第一条路线从(1,1),走到(x1,k-x1),第二条路线(1,1)走到f(x2,k-x2)的路线组成的集合
属性:
max
可以考虑:

 只走一次  f(i,j)
 走两次  f(x,y,x2,y2)
我们可以记录
f(k,x1,x2)//走k步,第一次走过的横坐标是x1,第二次为x2
状态计算

last 最后一步:
1、右右
2、右下
3、下右
4、下下
右右
第一条路线:(1,1)到(x1,k-1-x1);
第二条路线:(1,1)到(x2,k-1-x2);
右下
第一条路线:(1,1)到(x1,k-1-x1);
第二条路线:(1,1)到(x2-1,k-x2);
下右
第一条路线:(1,1)到(x1-1,k-x1);
第二条路线:(1,1)到(x2,k-1-x2);
下下
第一条路线:(1,1)到(x1-1,k-x1);
第二条路线:(1,1)到(x2-1,k-x2);

我们要考虑范围
1<=x1<=n;
1<=k-x1<=m;
x1<=k-1;
x1>=k-m;
max(1,k-m)<=x1<=min(k1,n);
f(k,x1,x2)=max(f(k,x1,x2),f(k-1,x1,x2))+t;

#include <iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N=55;
#define ll long long
int n,m;
int w[N][N];
int f[N<<1][N][N];
int main()
{
    int i,j,k;
    cin>>n>>m;

    for(i=1; i<=n; i++)
        for(j=1; j<=m; j++)
            cin>>w[i][j];

    for(k=2; k<=n+m; k++)
    {

        for(int x1=max(1,k-m); x1<=min(k-1,n); x1++)
            for(int x2=max(1,k-m); x2<=min(k-1,n); x2++)
            {
                int t=w[x1][k-x1];
                if(x2!=x1)//走的不是重复路线,就可以把对应w值加上。
                    t+=w[x2][k-x2];
                    //这里说一下为什么题目说不能走相同路线,这里却暗涵可以走相同路线了呢?
                    //原因是这里的状态属性是max,走相同路线不会加权值,那么就不会是最大值,跟最大值没有任何影响
                    //举个不太恰当例子:
                    //两个集合求最大值,即使集合有重合部分,也不会影响最后的最大值
                for(int a=0; a<=1; a++)
                    for(int b=0; b<=1; b++)
                        f[k][x1][x2]=max(f[k][x1][x2],f[k-1][x1-a][x2-b]+t);
            }
    }

    printf("%d",f[m+n][n][n]);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值