算法很美之贪心策略与动态规划

第八篇 算法很美之贪心策略与动态规划

题目1 :01背包

描述

且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了!

小Ho现在手上有M张奖券,而奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要need(i)张奖券进行兑换,同时也只能兑换一次,为了使得辛苦得到的奖券不白白浪费,小Ho给每件奖品都评了分,其中第i件奖品的评分值为value(i),表示他对这件奖品的喜好值。现在他想知道,凭借他手上的这些奖券,可以换到哪些奖品,使得这些奖品的喜好值之和能够最大。

提示一:合理抽象问题、定义状态是动态规划最关键的一步

提示二:说过了减少时间消耗,我们再来看看如何减少空间消耗
输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为两个正整数N和M,表示奖品的个数,以及小Ho手中的奖券数。

接下来的n行描述每一行描述一个奖品,其中第i行为两个整数need(i)和value(i),意义如前文所述。

测试数据保证

对于100%的数据,N的值不超过500,M的值不超过10^5

对于100%的数据,need(i)不超过2*10^5, value(i)不超过10^3
输出

对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的总喜好值。
样例输入

5 1000
144 990
487 436
210 673
567 58
1056 897

样例输出

2099
#include <stdio.h>
 
int dp[100001];
int need[501];
int value[501];

int max(int a,int b)
{
	return a>b?a:b;
 } 
 
void fill(int l, int r, int kk)
{
	int i;
	for(i=l;i<r;i++)
		dp[i]=kk;
}
 
int main()
{
	//freopen("in.txt","r",stdin);
	
    int n,m,i,j;
    scanf("%d%d",&n,&m);
    
    for(i=1; i<=n; i++)
    	scanf("%d%d",&need[i],&value[i]);
 
    fill(0,m+1,0);
    
    for( i=1; i<=n; i++)
        for( j=m; j>=1; j--)    //节省空间重复利用一维数组,因为dp[i]只需要用到本身和前面dp[i-need[i]],所以从后面开始更新
	    {
	        if( j>=need[i])
	        dp[j] = max( dp[j-need[i]]+value[i], dp[j]);
	    }
    printf("%d\n",dp[m]);
    
    //fclose(stdin);
    return 0;
}

题目2 :数字三角形

问题描述

小Hi和小Ho在经历了螃蟹先生的任务之后被奖励了一次出国旅游的机会,于是他们来到了大洋彼岸的美国。美国人民的生活非常有意思,经常会有形形色色、奇奇怪怪的活动举办,这不,小Hi和小Ho刚刚下飞机,就赶上了当地的迷宫节活动。迷宫节里展览出来的迷宫都特别的有意思,但是小Ho却相中了一个其实并不怎么像迷宫的迷宫——因为这个迷宫的奖励非常丰富~

于是小Ho找到了小Hi,让小Hi帮助他获取尽可能多的奖品,小Hi把手一伸道:“迷宫的介绍拿来!”

小Ho选择的迷宫是一个被称为“数字三角形”的n(n不超过200)层迷宫,这个迷宫的第i层有i个房间,分别编号为1…i。除去最后一层的房间,每一个房间都会有一些通往下一层的房间的楼梯,用符号来表示的话,就是从第i层的编号为j的房间出发会有两条路,一条通向第i+1层的编号为j的房间,另一条会通向第i+1层的编号为j+1的房间,而最后一层的所有房间都只有一条离开迷宫的道路。这样的道路都是单向的,也就是说当沿着这些道路前往下一层的房间或者离开迷宫之后,小Ho没有办法再次回到这个房间。迷宫里同时只会有一个参与者,而在每个参与者进入这个迷宫的时候,每个房间里都会生成一定数量的奖券,这些奖券可以在通过迷宫之后兑换各种奖品。小Ho的起点在第1层的编号为1的房间,现在小Ho悄悄向其他参与者弄清楚了每个房间里的奖券数量,希望小Hi帮他计算出他最多能获得多少奖券。

提示一:盲目贪心不可取,搜索计算太耗时

提示二:记忆深搜逞神威,宽度优先解难题

提示三:总结归纳提公式,减少冗余是真理
输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为一个正整数n,表示这个迷宫的层数。

接下来的n行描述这个迷宫中每个房间的奖券数,其中第i行的第j个数代表着迷宫第i层的编号为j的房间中的奖券数量。

测试数据保证,有100%的数据满足n不超过100

对于100%的数据,迷宫的层数n不超过100

对于100%的数据,每个房间中的奖券数不超过1000

对于50%的数据,迷宫的层数不超过15(小Ho表示2^15才3万多呢,也就是说……)

对于10%的数据,迷宫的层数不超过1(小Hi很好奇你的边界情况处理的如何?~)

对于10%的数据,迷宫的构造满足:对于90%以上的结点,左边道路通向的房间中的奖券数比右边道路通向的房间中的奖券数要多。

对于10%的数据,迷宫的构造满足:对于90%以上的结点,左边道路通向的房间中的奖券数比右边道路通向的房间中的奖券数要少。
输出

对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的最多奖券数。
样例输入

5
2
6 4
1 2 8
4 0 9 6
6 5 5 3 6

样例输出

28
#include<stdio.h>
int max(int a,int b)
{
	if(a>b)
		return a;
	else
		return b; 
}

main()
{
	int n,ans=0,i,j,b[200][200]; 
	
	scanf("%d",&n);
	for(i=0;i<n;i++)
		for(j=0;j<=i;j++)
		{
			scanf("%d",&b[i][j]);
		}
			
	
	for (i=n-2; i>=0; i--)
        for (j = 0; j<= i; j++)
            b[i][j]+= max(b[i+1][j], b[i+1][j+1]);
            
	printf("%d\n",b[0][0]);
	
	return 0;
}

题目3 :回文字符串

描述

给定一个字符串 S ,最少需要几次增删改操作可以把 S 变成一个回文字符串?

一次操作可以在任意位置插入一个字符,或者删除任意一个字符,或者把任意一个字符修改成任意其他字符。
输入

字符串 S。S 的长度不超过100, 只包含’A’-‘Z’。
输出

最少的修改次数。
样例输入

ABAD

样例输出

1
#include <stdio.h>
#include<string.h>

#define N 1005;
//const int N = 1005;
int dp[1005][1005];

int min(int a,int b)
{
	return a<b?a:b;
}

int minn(int a, int b, int c)
{
    return min(min(a, b), c);
}
int main()
{
	//freopen("in.txt","r",stdin); 
	
    char str[105];
    scanf("%s",str);
    int len,i,j;
    len=strlen(str);
    memset(dp, 0, sizeof(dp));
    for(i=len-1; i>=0; i--)
    {
        for(j=i+1; j<len; j++)
        {
            if(str[i] == str[j])
                dp[i][j] = dp[i+1][j-1];
            else
                dp[i][j] = minn(dp[i+1][j], dp[i][j-1], dp[i+1][j-1]) + 1;
        }
    }
    printf("%d\n",dp[0][len-1]);
    
    //fclose(stdin);
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44391957/article/details/87904709