注册 登录
编程论坛 C语言论坛

求助 dp问题 实在是想不出来

xiaohuo66 发布于 2020-11-27 20:21, 2241 次点击
给定n个物品,每个物品有其价值和价格。要求你从中选择至少m个物品,最大化选择的物品的价值之和除以价格之和(即总的性价比)。

Input
第一行一个整数T(1 <= T <= 10),表示数据组数。接下来T组数据:

对于每组数据,第一行两个整数n和m(1 <= m <= n <= 10000),表示物品个数和需要选择的个数。

接下来n行,第i行两个整数Ai和Bi(1 <= Ai,Bi <= 1e8),Ai表示第i个物品的价值,Bi表示第i个物品的价格。

Output
对于每组数据,输出一行,格式为:"Case #K: ANS",其中K表示当前是第K组数据。ANS表示最大的性价比,要求保留小数点后两位小数("%.2f"格式输出即可)。

Sample Input
2

3 2

1000 10

1000 100

1 1

10 6

183 94

1626 3880

306 104

246 1408

969 1936

3456 1660

2161 192

1931 4821

15011 484

1205 25212

Sample Output
Case #1: 91.00

Case #2: 5.42
10 回复
#2
xiaohuo662020-11-27 20:36
这应该是背包问题?
#3
xiaohuo662020-11-28 10:06
回复 2楼 xiaohuo66
二分答案??
#4
xiaohuo662020-11-28 10:09
回复 2楼 xiaohuo66
贪心+二分??
最大得选 考虑bi小的??
#5
xiaohuo662020-11-28 10:38
回复 5楼 xiaohuo66
没看懂 他不是让求的sum价值/sum价格吗 不能用单一的来表示吧
#6
xiaohuo662020-11-28 10:41
回复 5楼 xiaohuo66
您这样贪心明显不过样例吧
#7
rjsp2020-11-28 12:14
回复 6楼 xiaohuo66
按性价比确实不行,
100/10,90/100,8/10 性价比从高到底
但 (100+8)/(10+10) 大于 (100+90)/(10+100)
#8
xiaohuo662020-11-28 12:33
回复 6楼 xiaohuo66
#include <stdio.h>
#include <math.h>
#define max(a,b) a<b?b:a
float a[10005];
float b[10005];
float c[10005];
void Swap(int *p, int *q)
{
    int buf;
    buf = *p;
    *p = *q;
    *q = buf;
    return;
}

void QuickSort(int *a, int low, int high)
{
    int i = low;
    int j = high;
    int key = a[low];
    if (low >= high) //如果low >= high说明排序结束了
    {
        return ;
    }

    while (low < high) //该while循环结束一次表示比较了一轮
    {
        while (low < high && key <= a[high])
        {
            --high; //向前寻找
        }
        if (key > a[high])
        {
            Swap(&a[low], &a[high]);
            ++low;
        }
        while (low < high && key >= a[low])
        {
            ++low; //向后寻找
        }
        if (key < a[low])
        {
            Swap(&a[low], &a[high]);
            --high;
        }
    }
    QuickSort(a, i, low-1); //用同样的方式对分出来的左边的部分进行同上的做法
    QuickSort(a, low+1, j); //用同样的方式对分出来的右边的部分进行同上的做法
}
int check(int mid,int n,int m)
{
    float sum = 0;
    for(int j = 1 ; j <= n ; j++)
    {
        c[j] = a[j] - mid*b[j];
    }
    QuickSort(c,c[1],c[n]);
    for(int j = 1 ; j <= m ; j++)
    {
        sum += c[j];
    }
    if(sum < 0)return 1;
    else return 0;
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int i = 1 ; i <= t ; i++)
    {
        int n,m;
        float r = -1,ans = 0;
        scanf("%d%d",&n,&m);
        for(int j = 1 ; j <= n ; j++)
        {
            scanf("%f%f",&a[j],&b[j]);
            r = max(a[j]/b[j],r);
        }
        printf("Case #%d: ",i);
        float l = 0,mid;
        while(r-l>0.001)
        {
            mid = (l+r)/2;
            if(check(mid,n,m))
            {
                l = mid;
            }
            else
            {
                r = mid;
            }
        }
        printf("%0.2f\n",mid);
    }
    return 0 ;
}


[此贴子已经被作者于2020-11-28 18:04编辑过]

#9
请输入密码2020-11-28 12:44
当时看过算法是以背包重量+1递增弄的。大概意思就是知道重量为n的最大值是重量为(n-k)的最大值加k的价值的最大值。如果要求求出组合那就需要一个二维数组。然后回溯就行了。(印象中不能重复拿的也要用二维数组做重复标记,如果能重复拿那代码会简单很多)

当然算法代码我陌生,原地起稿弄得花很多时间精力,做不起做不起。当然模板网上也是大把大把的。
还有论坛有搜索功能。

市场告诉你在哪了,想吃瓜就自己争取去。

[此贴子已经被作者于2020-11-28 12:46编辑过]

#10
xiaohuo662020-11-28 12:51
回复 9楼 请输入密码
这么大数据 动态规划肯定tle(超时) 这题最理想就是二分答案 代码我写在上面了 但是跟样例差点意思....
#11
rjsp2020-11-30 10:11
写了一段代码,但我没法验证它是否正确

程序代码:
#include <stdio.h>

typedef struct {
    unsigned a;
    unsigned b;
} pair;

static pair foo_( pair p[], unsigned n, unsigned m, pair cur )
{
    if( m == 0 )
        return cur;

    double cpr = 0;
    unsigned index = 0;
    for( unsigned i=0; i!=n; ++i )
    {
        if( p[i].a != 0 )
        {
            if( cpr < (p[i].a + cur.a)*1.0/(p[i].b + cur.b) )
            {
                cpr = (p[i].a + cur.a)*1.0/(p[i].b + cur.b);
                index = i;
            }
        }
    }
    pair t = { p[index].a+cur.a, p[index].b+cur.b };
    p[index].a = 0;
    return foo_(p,n,m-1,t);
}
double foo( pair p[], unsigned n, unsigned m )
{
    pair r = foo_( p, n, m, (pair){0,0} );
    return r.a*1.0/r.b;
}

int main( void )
{
    unsigned t;
    scanf( "%u", &t );
    for( unsigned i=0; i!=t; ++i )
    {
        pair p[10000];
        unsigned n, m;
        scanf( "%u%u", &n, &m );
        for( unsigned j=0; j!=n; ++j )
            scanf( "%u%u", &p[j].a, &p[j].b );
        printf( "Case #%u: %.2f\n", i+1, foo(p,n,m) );
    }
}
1