HDU 4395 D-mail(DP)

来源:互联网 发布:c语言运算符结合方向 编辑:程序博客网 时间:2024/05/15 20:04

题目链接:Click here~~

题意:

给 n 个数字,选取一些取它们的和 S,取和的过程中 S 不能超过2,求出最接近目标数字 D 的 S。(数字均为 4 位小数)

解题思路:

很明显的 dp 模型,状态 dp[i][j] 表示前 i 个数字是否能取到和为 j 的情况。

由于条件的限制,第一维可以滚动,第二维的有效区间为 [-20,2] , 映射成整数是 [-200000,20000],再向右平移得到 [0,220000]。

由于 “取和的过程中 S 不能超过2” ,那么采取贪心的策略,先取小的,即对 w 排序后再 dp。

需要注意的是:1、double 转 int 时还要加个 eps。 2、由于使用了滚动数组,当 w[i] 为负数时 循环的方向要改变。

思路明朗后,代码也不难。

#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;const int N = 2e5 + 2e4;const int shift = 2e5;bool reach[N];int w[205];inline int read(){    double x;    scanf("%lf",&x);    if(x > 0)        return x * 10000 + 1e-8;    else        return x * 10000 - 1e-8;}int main(){    int T,n;    scanf("%d",&T);    while(T--)    {        memset(reach,false,sizeof(reach));        int goal = read();        scanf("%d",&n);        for(int i=0;i<n;i++)            w[i] = read();        sort(w,w+n);        reach[ 0 + shift ] = true;        for(int i=0;i<n;i++)        {            bool f = w[i] > 0;            if(f)            {                for(int j=N-1-w[i];j>=0;j--)                    if(reach[j])                        reach[ j + w[i] ] = true;            }            else            {                for(int j=-w[i];j<N;j++)                    if(reach[j])                        reach[ j + w[i] ] = true;            }        }        int i = goal + shift , j = 0;        int ans = -1;        while(1)        {            if(i-j >= 0 && reach[i-j])            {                ans = i - j;                break;            }            if(i+j < N && reach[i+j])            {                ans = i + j;                break;            }            ++j;        }        printf("%.4f\n",(ans-shift)/10000.0);    }    return 0;}


原创粉丝点击