http://acm.hdu.edu.cn/showproblem.php?pid=1203
简单的01背包问题,与其他的区别在于,要利用“至少得到一份”的对立面的概率去计算,所以,要把每个概率变成1-x,然后求背包最小,记得+wi要改成*wi就可以了,
其中还有一个初始化的问题,初始化为无穷大,而这里只需大于等于1就可以了,因为概率最大也就1,这样的比较最小时可以避免没有数值却依然被因为比较出来是最小而存数值进去的错误,这里可以用一维数组,或者滚动数组,两个版本都贴下
1 /*这里用的是滚动数组,时间46ms*/ 2 #include<stdio.h> 3 #include<string.h> 4 double dp[2][10001]; 5 double min(double a,double b) 6 { 7 return a>b?b:a; 8 } 9 int main() 10 { 11 int n,m,a[10001],i,j; 12 double b[10001]; 13 while(scanf("%d%d",&n,&m),n||m) 14 { 15 for(i=0;i<2;i++) 16 for(j=0;j<10001;j++) 17 dp[i][j]=1;//这里的初始化是为了在下面求最小时不会出现错误解,因为在 min(dp[(i-1)%2][j],dp[(i-1)%2][j-a[i]]*b[i]);中最大就是1,所以当两者之间有某个原先没有值的话,就可以让1来避免这个过程 18 for(i=1;i<=m;i++) 19 { 20 scanf("%d%lf",&a[i],&b[i]); 21 b[i]=1.0-b[i]; 22 } 23 for(i=1;i<=m;i++) 24 for(j=0;j<=n;j++) 25 { 26 if(j<a[i])dp[i%2][j]=dp[(i-1)%2][j]; 27 else dp[i%2][j]=min(dp[(i-1)%2][j],dp[(i-1)%2][j-a[i]]*b[i]); 28 } 29 //printf("%lf ",dp[m][n]); 30 printf("%.1lf%% ",(1.0-dp[m%2][n])*100.0); 31 } 32 return 0; 33 }
一维数组:
for i=1..N
for v=V..a[i]
f[v]=max{f[v],f[v-a[i]]*b[i]};从前往后推,每次f[v]保存的都是i之前最小的那个量,所以f[v]能得到最后的结果
1 /*这里用的是一维数组,时间ms*/ 2 #include<stdio.h> 3 #include<string.h> 4 double dp[10001]; 5 double min(double a,double b) 6 { 7 return a>b?b:a; 8 } 9 int main() 10 { 11 int n,m,a[10001],i,j; 12 double b[10001]; 13 while(scanf("%d%d",&n,&m),n||m) 14 { 15 for(j=0;j<10001;j++) 16 dp[j]=1;//这里的初始化是为了在下面求最小时不会出现错误解,因为在 min(dp[(i-1)%2][j],dp[(i-1)%2][j-a[i]]*b[i]);中最大就是1,所以当两者之间有某个原先没有值的话,就可以让1来避免这个过程 17 //出现乘法时也不会被0乘为0 18 for(i=1;i<=m;i++) 19 { 20 scanf("%d%lf",&a[i],&b[i]); 21 b[i]=1.0-b[i]; 22 } 23 for(i=1;i<=m;i++) 24 for(j=n;j>=a[i];j--) 25 dp[j]=min(dp[j],dp[j-a[i]]*b[i]);//这里以cost为参数进行计算 26 //printf("%lf ",dp[m][n]); 27 printf("%.1lf%% ",(1.0-dp[n])*100.0); 28 } 29 return 0; 30 }