OJ《程序设计基础II》实验6——动态规划

6-1 A - 递归的函数

#include <stdio.h>
int p[31][31][31];
int f(int a,int b,int c)
{
    if(a<=0||b<=0||c<=0) return 1;//返回值为1的是单独的一个判断程序
    if(p[a][b][c]>0) return p[a][b][c];//从这里开始,是返回值为函数值的判断程序,如果p[a][b][c]>0,意味着已经判断过一次,直接返回就行,不需要再判断了,这样就不会超时了
    else if(a>20||b>20||c>20) return p[a][b][c]=f(20,20,20);
    else if(a<b&&b<c) return p[a][b][c]=f(a,b,c-1)+f(a,b-1,c-1)-f(a,b-1,c);
    else return p[a][b][c]=f(a-1,b,c)+f(a-1,b-1,c)+f(a-1,b,c-1)-f(a-1,b-1,c-1);
}
int main()
{
    int a,b,c;
    while(~scanf("%d %d %d",&a,&b,&c))
    {
        printf("%d\n",f(a,b,c));
    }
    return 0;
}
 

6-2 B - 数字三角形问题

#include <stdio.h>
int max(int a,int b)
{
    return a>b?a:b;//判断大小函数,如果a>b,输出a,否则输出b 
}
int a[101][101];
int ans[101][101];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        ans[n][i]=a[n][i];
	}//将ans的最后一行赋值 
    for(int i=n-1;i>=1;i--)
    {
        for(int j=1; j<=i; j++)
        {
            ans[i][j]=max(ans[i+1][j],ans[i+1][j+1])+a[i][j];//只能向下或者向右下走,所以判断下或者右下哪个大就好 
        }
    }
    printf("%d\n",ans[1][1]);
    return 0;
}
 

6-3 C - 小鑫去爬山

#include <stdio.h>
int min(int a,int b)//构造函数筛选最小值 
{
    return a<b?a:b;
}
int a[101][101];
int ans[101][101];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=i; j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        for(int i=1; i<=n; i++)
        {
            ans[n][i]=a[n][i];//将第n行赋值,方便后面选择 
        }
        for(int i=n-1; i>=1; i--)//相当于一行一行往上走 
        {
            for(int j=1; j<=i; j++)
            {
                ans[i][j]=min(ans[i+1][j],ans[i+1][j+1])+a[i][j];//选择下一行的j和j+1列中较小的一个进行相加 
            }
        }//与上题差不多 
        printf("%d\n",ans[1][1]);
    }
    return 0;
}

 6-4 D - 最长公共子序列问题

#include <stdio.h>
#include <string.h>
int max(int a,int b)//构造max函数,筛选最大值 
{
    return a>b?a:b;
}
int main()
{
    char s1[501],s2[501];
    int n1,n2,a[501][501];
    while(~scanf("%s %s",s1,s2))
    {
        n1=strlen(s1);
        n2=strlen(s2);
        for(int i=0;i<=n1;i++)
        {
            a[i][0]=0;
        }
        for(int i=0;i<=n2;i++)
        {
            a[0][i]=0;
        }//以s1+1的长度为行,s2+1的长度位列,赋值矩阵 首行首列为0 
        for(int i=1;i<=n1;i++)
        {
            for(int j=1;j<=n2;j++)
            {
                if(s1[i-1]==s2[j-1])
                {
                  a[i][j]=a[i-1][j-1]+1;
                }
                else
                a[i][j]=max(a[i-1][j],a[i][j-1]);
            }
        }
            printf("%d\n",a[n1][n2]);
    }
    return 0;
}
 

和上图差不多的,需要理解,不好讲;

6-5 E - 最长上升子序列

#include <stdio.h>
#include <string.h>
int max(int a,int b)//max函数,筛选最大值 
{
    return a>b?a:b;
}
int main()
{
    int n,a[1001],b[1001];
    scanf("%d",&n);
    for(int i=0; i<n; i++)
    {
        scanf("%d",&a[i]);
        b[0]=1;//初始化边界条件,以a[0]结尾的最长上升子序列长度为1 
    }
    for(int i=1;i<n;i++)//让i从1开始,计算以a[i]结尾的最长上升子序列长度 
    {
        int Max=0;//j<i时最长上升子序列长度 
        for(int j=0;j<i;j++)
        {
            if(a[i]>a[j]&&b[j]>Max)//若a[j]<a[i]且Max小于以a[j]为结尾的最长上升子序列 
                Max=b[j];//则为Max赋新值 
        }
        b[i]=Max+1;//则以b[i]结尾的最长上升子序列为以b[j]结尾的最长上升子序列+1 
    }
    int ans=-1;
    for(int i=0;i<n;i++)
    {
        ans=max(ans,b[i]);//筛选以b[i]结尾的最长上升子序列的长度的最大值 
    }
    printf("%d",ans);
    return 0;
}
 

6-6 F - 上升子序列

#include <stdio.h>
#include <string.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int main()
{
    int n,a[1001],b[1001];
    while(~scanf("%d",&n))
    {
        for(int i=0; i<n; i++)
    {
        scanf("%d",&a[i]);
    }
    b[0]=a[0];//以b[0]结尾的最大上升子序列和为a[0] 
    for(int i=1;i<n;i++)//下面和上题几乎一模一样,不做过多赘述 
    {
        int Max=0;
        for(int j=0;j<i;j++)
        {
            if(a[i]>a[j]&&b[j]>Max)
                Max=b[j];
        }
        b[i]=Max+a[i];
    }
    int ans=-1;
    for(int i=0; i<n; i++)
        ans=max(ans,b[i]);
    printf("%d\n",ans);
    }
 
    return 0;
}
 

6-7 G - 最长公共子序列

不懂,直接放学长大佬的

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char a[110][110];
int dp[30000 + 10];
int len[110];
int n;
int DP( int *x )//x记录每个字符串的动态长度,即每个状态对应的每个字符串长度,这里需要一定理解,每个状态可以想成把一部分字符串丢掉,即长度减少
{
    int i, j, index, ret;
    for( i = 1; i <= n; i++ )//如果有一个字符串的长度为0,那么最长公共子序列必定为0
    {
        if( x[i] == 0 )
        {
            return 0;
        }
    }
    for( index = x[n] - 1, i = n - 1; i >= 1; i-- )
    {
        index = index * len[i] + x[i] - 1; //转化为一维数组,这里可以自己推导一下,上面分享的博客里有解释
    }
    if( dp[index] >= 0 )//如果之前求过这个状态直接返回,减少重复计算,dp的核心思想
    {
        return dp[index];
    }
    //从每个字符串的末尾开始匹配
    for( i = 2; i <= n; i++ )
    {
        if( a[1][x[1] - 1] != a[i][x[i] - 1] )
        {
            break;
        }
    }
    if( i > n )//如果都相等则把字符串长度都-1,答案就行-1后字符串求dp的答案+1
    {
        for( j = 1; j <= n; j++ )
        {
            x[j]--;
        }
        ret = DP(x) + 1;//dp求得长度-1的字符串状态的最长+1
        for( j = 1; j <= n; j++ )
        {
            x[j]++;
        }
    }
    else
    {
        ret = 0;
        int t;
        //开始枚举每一种情况,取最大值保留
        for( j = 1; j <= n; j++ )
        {
            x[j]--;
            t = DP( x );
            ret = max( ret, t );
            x[j]++;
        }
    }
    dp[index] = ret;//记忆化
    return ret;
}
int main()
{
    int T;
    int L[110];
    scanf("%d", &T);
    while( T-- )
    {
        scanf("%d", &n);
        for( int i = 1; i <= n; i++ )
        {
            scanf("%s",a[i] );
            len[i] = L[i] = strlen( a[i] );
        }
        memset( dp, -1, sizeof(dp) );
        printf("%d\n", DP( L ) );
    }
    return 0;
}

6-8 H - 取数字问题

#include <stdio.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int n,m;
int ans=0x3f3f3f3f,a[11][11];//ans设为int范围的最大值,用于下面验证。
void dp(int i,int j,int sum)//i,j表示现在在哪个点,sum表示从原点到(i,j)的和
{
    sum=sum+a[i][j];
    if(i<m-1)//如果没到最下边,则继续往下走,i+1表示向下一行的意思
        dp(i+1,j,sum);
    if(j<n-1)//如果没到最右边,则继续向右走
        dp(i,j+1,sum);
    if(i==m-1&&j==n-1&&sum>0&&sum<ans)//到达右下角了,判断这条路是否满足正数最小
        ans=sum;
}
int main()
{
    scanf("%d %d",&m,&n);
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    dp(0,0,0);//从原点开始
    if(ans==0x3f3f3f3f)//如果ans值不变,意味着不能得到正整数 
        printf("-1");
    else
    printf("%d",ans);
    return 0;
}

6-9 I - 免费馅饼

#include<stdio.h>
#include<string.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int dp[100001][15];
int main()
{
    int n;
    while(~scanf("%d",&n)&&n!=0)
    {
        int t1=0;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            int x,t;
            scanf("%d %d",&x,&t);
            t1=max(t1,t);
            dp[t][x]++;
        }
        for(int i=t1-1;i>=0; i--)
        {
            dp[i][0]=dp[i][0]+max(dp[i+1][0],dp[i+1][1]);
            for(int j=1;j<=10;j++)
            {
                dp[i][j]=dp[i][j]+max(max(dp[i+1][j-1],dp[i+1][j]),dp[i+1][j+1]);
            }
        }
        printf("%d\n",dp[0][5]);
    }
    return 0;
}

6-10 J - 走迷宫

不怎么明白就不乱解释了,放学长大佬代码

#include<stdio.h>
#include<string.h>
struct node
{
    int x, y;
} ls[1000];
int dx[] = {0,-1,0,1}, dy[] = {-1,0,1,0};
int bj[16][16], map[16][16];
int m, n, step, sum = 0, xz, yz;
void dfs(int x1, int y1)
{
    int i;
    if(x1 == xz && y1 == yz)
    {
        sum++;
        for(i = 0; i < step; i++)
        {
            printf("(%d,%d)",ls[i].x,ls[i].y);
            if(i < step - 1)
                printf("->");
        }
        printf("\n");
    }
    else
    {
        int kx, ky;
        for(i = 0; i < 4; i++)
        {
            kx  = x1 + dx[i];
            ky =  y1 + dy[i];
            if(kx >= 1 && ky >= 1 && kx <= n && ky <= m && !bj[kx][ky] && map[kx][ky])
            {
                ls[step].x = kx;
                ls[step].y = ky;
                step++;
                bj[kx][ky] = 1;
                dfs(kx,ky);
                bj[kx][ky] = 0;
                step--;
            }
        }
    }
}
int main()
{
    int i, j,xq,yq;
    while(~scanf("%d%d",&n,&m))
    {
        memset(bj,0,sizeof(bj));
        memset(ls,0,sizeof(ls));
        for(i = 1; i <= n; i++)
            for(j = 1; j <= m; j++)
                scanf("%d",&map[i][j]);
        scanf("%d%d%d%d",&xq,&yq,&xz,&yz);
        ls[0].x = xq;
        ls[0].y = yq;
        sum = 0;
        step = 1;
        bj[xq][yq] = 1;
        dfs(xq,yq);
        if(sum == 0)
            printf("-1\n");
    }
    return 0;
}
 

加油加油加油!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CRAEN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值