SCAU 2020寒训 专题3——动态规划

B - Is Bigger Smarter? UVA - 10131

1.题目描述:
Some people think that the bigger an elephant is, the smarter it is. To disprove this, you want to take the data on a collection of elephants and put as large a subset of this data as possible into a sequence so that the weights are increasing, but the IQ’s are decreasing.

Input
The input will consist of data for a bunch of elephants, one elephant per line, terminated by the endof-file. The data for a particular elephant will consist of a pair of integers: the first representing its size in kilograms and the second representing its IQ in hundredths of IQ points. Both integers are between 1 and 10000. The data will contain information for at most 1000 elephants. Two elephants may have the same weight, the same IQ, or even the same weight and IQ.

Output
Say that the numbers on the i-th data line are W[i] and S[i]. Your program should output a sequence of lines of data; the first line should contain a number n; the remaining n lines should each contain a single positive integer (each one representing an elephant). If these n integers are a[1], a[2],…, a[n] then it must be the case that
W[a[1]] < W[a[2]] < … < W[a[n]]
and
S[a[1]] > S[a[2]] > … > S[a[n]]
In order for the answer to be correct, n should be as large as possible. All inequalities are strict: weights must be strictly increasing, and IQs must be strictly decreasing. There may be many correct outputs for a given input, your program only needs to find one.

Sample Input
6008 1300
6000 2100
500 2000
1000 4000
1100 3000
6000 2000
8000 1400
6000 1200
2000 1900

Sample Output
4
4
5
9
7

2.题意:
有人觉得呀,大象就是越大只越聪明(那蚂蚁呢?蚁人了解一下),我们主人公就想找一组数据反驳(有理有据!),他想找一组 体重严格单调上升智商严格单调下降 的大象组来作为证据(这样很不严谨啊,敲黑板!)。

3.思路:
从单调上升和单调下降就很容易想到——最长上升子序列LIS(Longest Increasing Subsequence),剩下的就是如何把两种子序列融合起来了,我们知道题目里是不限制数据的顺序的,只需要大象的编号而已。我们就可以先对一种条件进行排序,然后再选出在该排序下的LIS即可。对于大象的顺序,我们可以记录前一头来回溯找到顺序。

4.代码:


```cpp
//B - Is Bigger Smarter?
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
#define FAST ios::sync_with_stdio(false)
using namespace std;
struct  elephant
{
	int w,s,num;
}e[1010];
int p,ans=0,path[1010];
bool cmp(elephant a,elephant b){return a.s>b.s;}
void printpath(int i)
{
	if(ans--)
	{
		printpath(path[i]);
		cout<<e[i].num<<endl;
	}
}
int main()
{
	//freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
	int n=0,dp[1010];
	while(~scanf("%d%d",&e[n].w,&e[n].s))
	{
		e[n].num=n+1;
		dp[n]=1;
		path[n]=n;
		n++;
	}
	sort(e,e+n,cmp);
	for(int i=0;i<n;++i)
	{
		for(int j=0;j<i;++j)
		{
			if(e[i].w>e[j].w&&e[i].s<e[j].s&&dp[i]<dp[j]+1)
			{
				dp[i]=dp[j]+1;
				path[i]=j;
			}
			if(dp[i]>ans)
			{
				ans=dp[i];
				p=i;
			}
		}
	}
	cout<<ans<<endl;
	printpath(p);
	return 0;
}

C - Dividing coins UVA - 562

1.题目描述:
It’s commonly known that the Dutch have invented copper-wire. Two Dutch men were fighting over a nickel, which was made of copper. They were both so eager to get it and the fighting was so fierce, they stretched the coin to great length and thus created copper-wire.
Not commonly known is that the fighting started, after the two Dutch tried to divide a bag with
coins between the two of them. The contents of the bag appeared not to be equally divisible. The Dutch of the past couldn’t stand the fact that a division should favour one of them and they always wanted a fair share to the very last cent. Nowadays fighting over a single cent will not be seen anymore, but being capable of making an equal division as fair as possible is something that will remain important forever…
That’s what this whole problem is about. Not everyone is capable of seeing instantly what’s the most fair division of a bag of coins between two persons. Your help is asked to solve this problem.
Given a bag with a maximum of 100 coins, determine the most fair division between two persons. This means that the difference between the amount each person obtains should be minimised. The value of a coin varies from 1 cent to 500 cents. It’s not allowed to split a single coin.

Input
A line with the number of problems n, followed by n times:
• a line with a non negative integer m (m ≤ 100) indicating the number of coins in the bag
• a line with m numbers separated by one space, each number indicates the value of a coin.

Output
The output consists of n lines. Each line contains the minimal positive difference between the amount the two persons obtain when they divide the coins from the corresponding bag.

Sample Input
2
3
2 3 5
4
1 2 4 6
Sample Output
0
1

2.题意:
常言道:不患寡而患不均,在这道题体现得淋漓尽致啊~两位大哥要分钱,问怎么分才能使得到“最小正差异”(即:min(|a-b|))。

3.思路:
这题要转换一下思路,什么时候二者差异最小?——都取一半的钱啦。那么我们是不是要从一堆钱里面找到一种搭配使得我们主人公拿到的钱最接近总数的一半呢!(两个人对称,考虑哪个都无所谓。)想到这里其实就可以想到了—— 0-1背包问题。背包容量是 sum/2,每个物品的价值和重量相等。

4.代码:

//C - Dividing coins
#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
#define FAST ios::sync_with_stdio(false)
using namespace std;
int main()
{
	//freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
	long long Case;
	scanf("%lld",&Case);
	while(Case--)
	{
		int n,coins[100],sum=0,dp[25000+5]={0,0};
		cin>>n;
		for(int i=0;i<n;i++)
		{
			cin>>coins[i];
			sum+=coins[i];
		}
		for(int i=0;i<n;i++)
			for(int v=sum/2;v>0;v--)
				if(coins[i]<=v)
					dp[v]=max(dp[v],dp[v-coins[i]]+coins[i]);
		cout<<abs(sum-2*dp[sum/2])<<endl;
	}
	return 0;
}

F - Bachet’s Game UVA - 10404

1.题目描述:
Bachet’s game is probably known to all but probably not by thisname. Initially there are n stones on the table. There are twoplayers Stan and Ollie, who move alternately. Stan always starts. The legalmoves consist in removing at least one but not more than k stones from the table. The winner isthe one to take the last stone.
Here we consider a variation of this game. The number of stones that can be removed in a single move must be a member of a certain set of m numbers. Among the m numbers there is always 1 and thus the game never stalls.

Input
The input consists of a number of lines. Each line describes one game by a sequence of positive numbers.The first number is n ≤ 1000000 the number of stones on the table; the second number is m ≤ 10giving the number of numbers that follow; the last m numbers on the line specify how many stones can be removed from the table in a single move.

Output
For each line of input, output one line saying either ‘Stan wins’ or ‘Ollie wins’ assuming that both of them play perfectly.

Sample Input
20 3 1 3 8
21 3 1 3 8
22 3 1 3 8
23 3 1 3 8
1000000 10 1 23 38 11 7 5 4 8 3 13
999996 10 1 23 38 11 7 5 4 8 3 13

Sample Output
Stan wins
Stan wins
Ollie wins
Stan wins
Stan wins
Ollie wins

2.题意:
大概是两个无聊的人比赛拿石子(这事还得从一只蝙蝠说起?!),而Stan永远先手,谁最后莫得石子拿谁就输了呗。

3.思路:
典型的博弈问题,状态呢也很简单,一个人拿了K中的第j个石子(K是所给数字的集合),那么就会变为后手,所以是一个对称的思路。dp[i]如果赢,那么dp[i+k[j]]就是输的状态。

4.代码:

//F - Bachet's Game UVA - 10404
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX_N=1000000+5;
int n,m;
int k[10];
bool dp[MAX_N];
void solve()
{
	memset(dp,0,sizeof(dp));
	dp[1]=1;
	for(int i=0;i<=n;++i)
		for(int j=0;j<m;++j)
			if(i+k[j]<=n&&!dp[i])
				dp[i+k[j]]=1;
	if(dp[n]) cout<<"Stan wins"<<endl;
	else cout<<"Ollie wins"<<endl;
}
int main()
{
	//freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=0;i<m;++i)
			cin>>k[i];
		solve();
	}
	return 0;
}

//我会补完剩下的!QAQ

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值