您的位置:首页 > 其它

hiho一下 第145周

2017-04-11 17:08 183 查看


题目1 : 智力竞赛

时间限制:5000ms
单点时限:1000ms
内存限制:256MB


描述

小Hi、小Ho还有被小Hi强拉来的小Z,准备组队参加一个智力竞赛。竞赛采用过关制,共计N个关卡。在第i个关卡中,小Hi他们需要获得Ai点分数才能够进入下一关。每一关的分数都是独立计算的,即使在一关当中获得超过需要的分数,也不会对后面的关卡产生影响。
小Hi他们可以通过答题获得分数。答对一道题获得S点分数,答错一道题获得T点分数。在所有的N个关卡中,小Hi他们一共有M次答题机会。在每个关卡中,都可以在累计答题次数不超过M的情况下使用任意次的答题机会。
那么现在问题来了,对于给定的N、M、S、T和A,小Hi他们至少需要答对多少道题目才能够完成所有的关卡呢?


输入

每个输入文件包含多组测试数据,在每个输入文件的第一行为一个整数Q,表示测试数据的组数。
每组测试数据的第一行为四个正整数N、M、S和T,意义如前文所述。
第二行为N个正整数,分别表示A1~AN。
对于40%的数据,满足1<=N,M<=100
对于100%的数据,满足1<=N,M<=1000,1<=T<S<=10,1<=Ai<=50
对于100%的数据,满足1<=Q<=100


输出

对于每组测试数据,如果小Hi他们能够顺利完成关卡,则输出一个整数Ans,表示小Hi他们至少需要答对的题目数量,否则输出No。

样例输入
1
2 10 9 1
12 35


样例输出

5


《智力竞赛》题目分析

首先我们可以发现,由于每一关需要的分数Ai是固定的,所以如果确定第i关答错了x题,那么最少需要答对的题目数就是max{0, ⌈(Ai-xT)/S}⌉。
为了描述方便我们把这个值记为
c[i][x]
,
即第i关如果答错的题目数是x,那么这一关最少答对的题目数是
c[i][x]

于是这道题实际是让我们决策每一关答错多少题,才能使得在总答题次数不超过M的情况下,总答对的题目数最少。
这是一个比较典型的动态规划题目,比较容易想到可以令
f[i][j]
表示完成前i关如果总答错题目数是j次,最少需要的总答对题目数。
按关卡划分阶段,每次转移就是枚举第i关答错的题目数x,即
f[i][j] = min{f[i-1][j-x] +
c[i][x], | x = 0 .. ⌈Ai/T⌉}

最后我们要在所有f
[j],j=0..M中找到最小的j满足f
[j] + j <= M。
这个算法总状态数是O(NM)的,转移复杂度是O(max{Ai})的。对于极限数据还是可能超时。
另一种动态规划算法需要我们换一种状态表示。我们可以用
g[i][j]
表示答错i题,答对j题时,能达到的 最好记录 是什么。
这里记录用一个二元组(x, y)表示,其中x是关卡,y是得分。也就是说
g[i][j]=(x,
y)
表示答错i题,答对j题时,最高能进行到第x关,并且得分是y。
显然任何两个记录(x1, y1)和(x2, y2)都是可比较优劣的。同时为了描述方便,我们定义一个记录"加"得分的算子+,(x1, y1) + s = (x2, y2)表示:如果当前在第x1关y1分,那么再加s分之后,到达的是第x2关y2分。
我们可以按答题总数划分阶段,每次转移就是枚举最后一题是答对还是答错了:
g[i][j] = max{g[i-1][j] + T,
g[i][j-1] + S}

最后我们在所有
g[i][j]
里找到通过第n关,并且j最小的。
这个算法总复杂度是O(M^2),转移是O(1)的。

//
// Created by liyuanshuo.
// Author: LiAo/LiYuanShuo
// Time: 2017/4/11.
// CSDN blog: http://blog.csdn.net/liyuanshuo_nuc?skin=dark1 // 顺便骗点访问量(^_^)
//

#include <bits/stdc++.h>

using namespace std;

int dpp[1010][1010];
const int inf = 0x7f7f7f7f;
int array_a[1010];

int main( )
{
//freopen ("F:\\CSLeaning\\Thinking in C++\\hihocoder\\in.in", "r", stdin);

int q, n, m, s, t;
cin>>q;
while( q-- )
{
memset (dpp, inf, sizeof (dpp));
cin>>n>>m>>s>>t;
for (int i = 1; i <= n ; ++i)
{
cin>>array_a[i];
}
for (int j = 0; j <=m ; ++j)
{
dpp[0][j] = 0;
}
for (int k = 1; k <= n ; ++k)
{
int total_num = ( array_a[k]%s == 0 ) ? array_a[k]/s : array_a[k]/s+1 ;
for (int i = 0; i <= total_num ; ++i)
{
int tmp_x = array_a[k] - i*s;
if( tmp_x > 0 )
tmp_x = (tmp_x%t =
a236
= 0 ) ? tmp_x/t : tmp_x/t+1;
else
tmp_x = 0;
for (int j = 0; j+tmp_x+i <= m ; ++j)
{
dpp[k][i+j+tmp_x] = min (dpp[k][i+j+tmp_x], dpp[k-1][j]+i );
}
}
}
int ans = inf;
for (int l = 0; l <= m ; ++l)
{
ans = min (ans, dpp
[l]);
}
if( ans <= m )
cout<<ans<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hihicoder 动态规划