2023/2/7总结

P1216 [USACO1.5][IOI1994]数字三角形 Number Triangles

题目描述
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

在上面的样例中,从 7→3→8→7→57→3→8→7→5 的路径产生了最大
输入格式
第一个行一个正整数 � r ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
输出格式
单独的一行,包含那个可能得到的最大的和。
输入输出样例
输入 #1复制
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
输出 #1复制
30
说明/提示
【数据范围】
对于 100%100% 的数据,1≤�≤10001≤ r≤1000,所有输入在 [0,100][0,100] 范围内。
题目翻译来自NOCOW。
USACO Training Section 1.5
IOI1994 Day1T1
  1. 该题用逆向求解的方法从后往前递推。

  1. 先从三角形的倒数第二排开始算,每个数都有右下和左下两种选择,每次选择两者中最大的加起来。然后到倒数第三行,选择左下和右下两者中较大的加起来。以此类推,最大的路径和就是三角形的顶端。输出即可。

  1. 代码如下:

#include"stdio.h"
int a[1005][1005];
int n,ans=0;
int max(int x,int y)
{
    if(x>y) return x;
    return y;
}
main()
{
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=i;j++)
        scanf("%d",&a[i][j]);
        getchar();
    }
    for(i=n-1;i>=1;i--)
    {
        for(j=1;j<=i;j++)
        a[i][j]+=max(a[i+1][j],a[i+1][j+1]);//从左下,右下选取较大的加到现在的位置上
    }
    printf("%d",a[1][1]);
}

P1802 5 倍经验日

题目背景
现在乐斗有活动了!每打一个人可以获得 5 倍经验!absi2011 却无奈的看着那一些比他等级高的好友,想着能否把他们干掉。干掉能拿不少经验的。
题目描述
现在 absi2011 拿出了 � x 个迷你装药物(嗑药打人可耻…),准备开始与那些人打了。
由于迷你装药物每个只能用一次,所以 absi2011 要谨慎的使用这些药。悲剧的是,用药量没达到最少打败该人所需的属性药药量,则打这个人必输。例如他用 22 个药去打别人,别人却表明 33 个药才能打过,那么相当于你输了并且这两个属性药浪费了。
现在有 � n 个好友,给定失败时可获得的经验、胜利时可获得的经验,打败他至少需要的药量。
要求求出最大经验 � s,输出 5�5 s
输入格式
第一行两个数,� n 和 � x
后面 � n 行每行三个数,分别表示失败时获得的经验 ����� losei,胜利时获得的经验 ���� wini 和打过要至少使用的药数量 ���� usei
输出格式
一个整数,最多获得的经验的五倍。
输入输出样例
输入 #1复制
6 8 21 52 1 21 70 5 21 48 2 14 38 3 14 36 1 14 36 2
输出 #1复制
1060
说明/提示
【Hint】
五倍经验活动的时候,absi2011 总是吃体力药水而不是这种属性药。
【数据范围】
对于 10%10% 的数据,保证 �=0 x=0。
对于 30%30% 的数据,保证 0≤�≤100≤ n≤10,0≤�≤200≤ x≤20。
对于 60%60% 的数据,保证 0≤�,�≤1000≤ n, x≤100, 10<�����,����≤10010< losei, wini≤100,0≤����≤50≤ usei≤5。
对于 100%100% 的数据,保证 0≤�,�≤1030≤ n, x≤103,0<�����≤����≤1060< loseiwini≤106,0≤����≤1030≤ usei≤103。
【题目来源】
fight.pet.qq.com
absi2011 授权题目
  1. 这是一个01背包问题,不同的是该题在选或者不选都有相应的经验值。

  1. 注意在内循环遍历背包状态时要从0状态开始,因为有打不赢也有经验值的可能性。

  1. 输出时用long long 型记得*5。

  1. 代码如下:

  • 二维数组记录状态值:

#include"stdio.h"
struct node
{
    int lose, win, use;
}e[1005];
int dp[1005][1005];
int max(int x,int y)
{
    if(x>y) return x;
    return y;
}
main()
{
    int n,x,i,j;
    long long ans=0;
    scanf("%d %d",&n,&x);
    for(i=1;i<=n;i++) 
    scanf("%d %d %d",&e[i].lose,&e[i].win,&e[i].use);
    for(i=1;i<=n;i++)//要打的人 
    {
        for(j=0;j<=x;j++)//背包状态,从0开始因为有打不赢还有经验这种情况 
        {
            if(e[i].use<=j)//能打赢 
        {
            dp[i][j]=max(dp[i-1][j]+e[i].lose,dp[i-1][j-e[i].use]+e[i].win);
        }//选择打或不打 
        else dp[i][j]=dp[i-1][j]+e[i].lose;//打不赢 
        }    
     }
    ans=5*dp[n][x];
    printf("%lld",ans);
}
  • 一维滚动数组:

#include"stdio.h"
int dp[1005],win[1005],lose[1005],use[1005];
int n,x;
long long ans=0;
int max(int x,int y)
{
    if(x>y) return x;
    return y;
}
main()
{
    int i,j;
    scanf("%d %d",&n,&x);
    for(i=1;i<=n;i++)
    scanf("%d %d %d",&lose[i],&win[i],&use[i]);
    for(i=1;i<=n;i++)
    {
        for(j=x;j>=use[i];j--)
        dp[j]=max(dp[j]+lose[i],dp[j-use[i]]+win[i]);
        for(j=use[i]-1;j>=0;j--)
        dp[j]+=lose[i]; 
    }
    ans=5*dp[x];
    printf("%lld",ans);
}

你可能感兴趣的:(算法)