猥琐宅男——koko | ||||||
| ||||||
Description | ||||||
唔。。从前有个小胖子叫koko(QAQ。。。)很喜欢吃香蕉,茄子和黄瓜(唔。。好奇怪的癖好。。。),而且每天都必须且只能吃一个而且相邻两天不能吃一样的水果~(为什么必须吃一个?因为不吃会受不了,为什么只能吃一个?因为吃多了会受不了~)唔。由于这三种水果(水果!?)灰常可怕,可以吸收天地之间离散的邪恶值,所以呢koko希望你能帮他设计一种方案使得koko在n天内吃这三种水果获得的邪恶值最小~。
| ||||||
Input | ||||||
输入以T开头,代表有T组样例 每组样例第一行有一个整数n(1<=n<=40000),代表koko希望你帮他规划n天的饮食方案,接下来n行每行有三个数字,X, Q, H分别代表在这一天吃香蕉,茄子,和黄瓜会获得的邪恶值(1<=X, Q, H<=1000)
| ||||||
Output | ||||||
对于每一组样例输出可以获得的最小邪恶值 | ||||||
Sample Input | ||||||
2
4 13 23 12 77 36 64 44 89 76 31 78 45
3 26 40 83 49 60 57 13 89 99
| ||||||
Sample Output | ||||||
Case 1: 137 Case 2: 96 |
最开始用贪心算法,没过,系统反馈给我的是WA,然后我用LONG LONG INT SUM,还是WA,那就说明我的算法过程有错误了。
后来才知道,这是一道简单的dp题目,贪心不过的原因是,部分最优并非达到了结果最优(本次吃的最优,但是不代表总体吃完最优)。所以我们如果用贪心思想去做题,是一定WA的。
dp:
本次吃的方法无非就三种,要么吃1号,要么吃2号,要么吃3号,因为我们不知道怎么吃才能达到总体最优,所以我们干脆三种都一遍。
我们这里设置dp【40050】【3】的二维数组,表示i次上吃j的最优。假设我现在是第三次吃,那我要有三种吃法:j=1,j=2,j=3.都要吃一遍,因为dp【i】【j】表示的是第i次吃j的当前最优,所以我们这里第三次吃j=1的时候,我们要加上第二次的最优,而且本次吃j=1,就说明上一次不准吃1.所以我们这里要推出这样的一个状态转移方程式:
dp【i】【1】=a【i】【1】(食品编号)+min(dp【i】【1】,dp【i】【2】).
然后我们进行代码缩减,只用一个dp数组搞定:
#include<stdio.h>
#include<iostream>
using namespace std;
int dp[40050][3];
int main()
{
int kase=0;
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
for(int j=0;j<3;j++)
{
scanf("%d",&dp[i][j]);
}
}
for(int i=1;i<n;i++)
{
dp[i][0]=dp[i][0]+min(dp[i-1][1],dp[i-1][2]);
dp[i][1]=dp[i][1]+min(dp[i-1][0],dp[i-1][2]);
dp[i][2]=dp[i][2]+min(dp[i-1][0],dp[i-1][1]);
}
printf("Case %d: %d\n",++kase,min(dp[n-1][0],min(dp[n-1][1],dp[n-1][2])));
}
}