ZUST- 程序设计算法竞赛基础【4】

1001.数塔

题目:
Problem Description
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:

有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?
在这里插入图片描述
已经告诉你了,这是个DP的题目,你能AC吗?
Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
Sample Input
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
Sample Output
30
题目原址

解题思路:动态规划(dp),从下往上判断最大的加上去。

代码:

#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
int a[101][101];
int max(int x,int y)
{
    return x>=y?x:y;
}
void suan(int n)
{
    for(int i=n-1;i>=1;i--)
    {
        for(int j=n-1;j>=1;j--)
        {
            a[i][j]+=max(a[i+1][j],a[i+1][j+1]);
        }
    }
    printf("%d\n",a[1][1]);
}
int main()
{
    int N;
    scanf("%d",&N);
    while(N--)
    {
        int n;
        scanf("%d",&n);
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        suan(n);
    }
    return 0;
}

1002.连续最大积

题目:
Problem Description
小明和他的好朋友小西在玩一个游戏,由电脑随机生成一个由-2,0,2三个数组成的数组,并且约定,谁先算出这个数组中某一段连续元素的积的最大值,就算谁赢!

比如我们有如下随机数组:
2 2 0 -2 0 2 2 -2 -2 0
在这个数组的众多连续子序列中,2 2 -2 -2这个连续子序列的积为最大。

现在小明请你帮忙算出这个最大值。
Input
第一行输入一个正整数T,表示总共有T组数据(T <= 200)。
接下来的T组数据,每组数据第一行输入N,表示数组的元素总个数(1<= N <= 10000)。
再接下来输入N个由0,-2,2组成的元素,元素之间用空格分开。
Output
对于每组数据,先输出Case数。
如果最终的答案小于等于0,直接输出0
否则若答案是2^x ,输出x即可。
每组数据占一行,具体输出格式参见样例。
Sample Input
2
2
-2 0
10
2 2 0 -2 0 2 2 -2 -2 0
Sample Output
Case #1: 0
Case #2: 4
题目原址

解题思路:分情况讨论,遇到0,记录下乘积和-2,2的个数,判断乘积正负,然后重新开始,要注意,如果基数没有0,则为特殊情况。

代码:

#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
	int N,d,q;
	long long int sum;
	cin>>N;
	for(int i=0;i<N;i++)
	{
		int T;
		cin>>T;
		int a[T],b[T];
		memset(b,0,sizeof(b));
		d=0;
		q=0;
		sum=1;
		for(int j=0;j<T;j++)
		{
			cin>>a[j];
			if(a[j]==-2||a[j]==2)
			{
				d++;//个数
				sum*=a[j];
				b[q]=d;//如果都不为了,则可提前赋值,如果放在下面的if中,则不对
			}
			if(a[j]==0||j==(T-1))//遇到0,重新开始;或者所有基数都不为0,则到最后再考虑乘积正负
			{
				if(sum<0)
				{
					b[q]=0;
				}
				d=0;
				q++;//下一种
				sum=1;
			}
		}
		sort(b,b+T);
		cout<<"Case #"<<i+1<<": "<<b[T-1]<<endl;
	}
	return 0;
}

1003.Ignatius and the Princess IV

题目:
Problem Description
“OK, you are not too bad, em… But you can never pass the next test.” feng5166 says.

“I will tell you an odd number N, and then N integers. There will be a special integer among them, you have to tell me which integer is the special one after I tell you all the integers.” feng5166 says.

“But what is the characteristic of the special integer?” Ignatius asks.

“The integer will appear at least (N+1)/2 times. If you can’t find the right integer, I will kill the Princess, and you will be my dinner, too. Hahahaha…” feng5166 says.

Can you find the special integer for Ignatius?
Input
The input contains several test cases. Each test case contains two lines. The first line consists of an odd integer N(1<=N<=999999) which indicate the number of the integers feng5166 will tell our hero. The second line contains the N integers. The input is terminated by the end of file.
Output
For each test case, you have to output only one line which contains the special number you have found.
Sample Input
5
1 3 2 3 3
11
1 1 1 1 1 5 5 5 5 5 5
7
1 1 1 1 1 1 1
Sample Output
3
5
1
题目原址

解题思路:找规律,只要存在的个数大于总数的一半,那么排序过后,中间那个数就是要找的数

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
	int N;
	while(cin>>N)
	{
		int a[N];
		for(int i=0;i<N;i++)
		{
			cin>>a[i];
		}
		sort(a,a+N);//从小到大排列
		cout<<a[(N+1)/2-1]<<endl;
	}
	return 0;
}

1005.Bone Collector

题目:
Problem Description
Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?

Input
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
Output
One integer per line representing the maximum of the total value (this number will be less than 231).
Sample Input
1
5 10
1 2 3 4 5
5 4 3 2 1
Sample Output
14

题目原址

解题思路:动态规划,把从小到大不同情况体积时能装下的最大价值(用max函数)比较求出,输出最大时即总体积时的最大价值。

代码:

//给定物体的体积和价值,求能装的最大价值
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define m 1010
int dp[m],v[m],w[m];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        memset(v,0,sizeof(v));
        memset(w,0,sizeof(w));
        int n,V;
        cin>>n;//骨头个数 
        cin>>V;//总体积 
        int i,j;
        for(i=1;i<=n;i++)
        {
            cin>>v[i];//每个的价值 
         } 
        for(i=1;i<=n;i++)
        {
            cin>>w[i];//每个的体积 
        }
        for(i=1;i<=n;i++)
        {
            for(j=V;j>=w[i];j--)
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);//从体积小的开始算 
        }
        cout<<dp[V]<<endl; 
    }
    return 0;
 } 

1007.最少拦截系统

题目:
Problem Description
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.
怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.
Input
输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)
Output
对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统.
Sample Input
8 389 207 155 300 299 170 158 65
Sample Output
2
题目原址

解题思路:挨个输入比较,这样更节省时间

代码:

#include <iostream>
using namespace std;
int main()
{
    int n,m,i,j,k,p,a[100000],b[100000];
    while(cin>>n)
    {
        cin>>a[0];
        b[0]=a[0];
        k=0;
        for(i=1;i<n;i++)
        {
            cin>>a[i];
            p=0;
            for(j=0;j<=k;j++)
            {
                if(b[j]>a[i])
                {b[j]=a[i];p=1;break;}//一次向后比较
            }
            if(p==0)b[++k]=a[i];
        }
        cout<<k+1<<endl;
    }
    return 0;
}  

总结:动态规划的各个子问题并非独立且是有限的,我们需要用数组来保存已经求出的答案,以此避免多次重复计算(无后效性)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值