HDU2955 Robberies 算法想的复杂了

好多年没写这种动态规划程序了,最近忽然想起来当年的爱好,写些ACM程序。

这题是个背包问题,然而背包的解法我忘光了。。。


在有AB两个银行时,抢某个银行被抓的概率的计算假设A为pA,B为pB

则p被抓=pA+(1-pA)*pB=pB+(1-pB)*pA

则p不被抓=(1-pA)*(1-pB) 故对输入全部用1减下

2就是这题目要对钱当做体积,求一个当前钱数的不被抓概率

之后就是01背包的过程不再做加法而是乘法了。

之前的我都想明白了,唯一没想明白的是01背包怎么做。。本来01背包一个个物品循环放进DP数组就好了,结果我循环写成了逐个对每个钱的金额来计算最优解,然后优化了下代码,虽然是3个for循环,但是认真算了下时间复杂度,也是n的平方,认真改了几个bug,最后也AC了。

写完之后看看别人的代码http://blog.sina.com.cn/s/blog_6cf509db0100sqgx.html,感觉我这题还是没想好算法就动手了,下次需要注意。 


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
    int n;
    double value;
}million_s;
#define DP_SIZE 105
million_s million[DP_SIZE][DP_SIZE];
int million_count[DP_SIZE];
int dp[DP_SIZE* DP_SIZE][DP_SIZE];
double dp_p[DP_SIZE*DP_SIZE];
//void qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*));
int cmp(const void *a, const void *b)
{
    if((((million_s *)a)->value < ((million_s *)b)->value))
return 1;
else if((((million_s *)a)->value == ((million_s *)b)->value))
return 0;
else
return -1;
}
int main()
{
    int t,i,n,j,k,l;
    double max_pro;
    int sum, max_m;
    double max_p;
    int temp_m;
    double temp_p;
    scanf("%d", &t);
    for(i = 0; i < t; i++)
    {
        scanf("%lf %d", &max_pro, &n);
max_pro = 1 - max_pro;
        memset(million_count, 0, sizeof(million_count));//初始化million_count
        for(sum = 0, j = 0, max_m = 0; j < n; j++)
        {
            scanf("%d %lf", &temp_m, &temp_p);
    temp_p = 1 - temp_p;
            sum += temp_m;
            if(temp_m > max_m)
                max_m = temp_m;
            million[temp_m][million_count[temp_m]].value = temp_p;//temp_m是价值,million_count[temp_m]是价值为temp_m的第几个,million[temp_m][million_count[temp_m]].value是价值为temp_m的概率
            million[temp_m][million_count[temp_m]].n = j;//n是价值为temp_m的第几个,从0开始
            million_count[temp_m]++;
        }
        for(j = 0; j < DP_SIZE; j++)
        {
            qsort(million[j], million_count[j], sizeof(million_s), cmp);//对million[j]排序,按价值从小到大排列
        }
        for(j = 1; j < DP_SIZE * DP_SIZE; j++)
{
dp_p[j] = 0;//初始化dp
}
dp_p[0] = 1.0;
        for(k = 1; k <= sum; k++)
        {
            memset(dp[k], 0, sizeof(int) * DP_SIZE);
            if(k <= max_m)
            {
                j = 0;
            }
            else
            {
                j = k - max_m;
            }
            max_p = 0;
            for(;j < k; j++)
            {
                 for(l = 0; l < million_count[k-j]; l++)
                 {
                     if(dp[j][million[k-j][l].n] == 1)
                     {
                         continue;
                     }


                     temp_p = dp_p[j] * million[k-j][l].value;
                     if(temp_p > max_p)
                     {
                         max_p = temp_p;
                         dp_p[k] = max_p;
                         memcpy(dp[k], dp[j], sizeof(int) * DP_SIZE);
                         dp[k][million[k-j][l].n] = 1;
                     }
                 }
            }
        }
max_m = 0;
        for(k = sum; k >= 0; k--)
{
if(dp_p[k] > max_pro)
{
max_m = k;
break;
}
}


printf("%d\n", max_m);
    }
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值