Robberies 点击打开链接
背包;第一次做的时候把概率当做背包(放大100000倍化为整数):在此范围内最多能抢多少钱 最脑残的是把总的概率以为是抢N家银行的概率之和… 把状态转移方程写成了f[j]=max{f[j],f[j-q[i].v]+q[i].money}(f[j]表示在概率j之下能抢的大洋);
正确的方程是:f[j]=max(f[j],f[j-q[i].money]*q[i].v) 其中,f[j]表示抢j块大洋的最大的逃脱概率,条件是f[j-q[i].money]可达,也就是之前抢劫过;
始化为:f[0]=1,其余初始化为-1 (抢0块大洋肯定不被抓嘛)
/*
由于目前实力有限,所以只能看讨论板里的说法
本题题意:实际就是一个01背包,去抢银行,但是他母亲需要测试一下是否安全,测试方法就是
找到一些银行的 被盗金额和盗取该金额的被抓的概率。求他在给定的安全概率下能抢的最多的钱
我们可以从相反的例子来探讨,就是讨论他逃跑的概率
所以每一次抢劫一次钱的逃跑概率就是P=1-P;
我们需要得到他不被抓的概率下的最大金额,dp[i]就是他的不被抓的概率
由初中的知识可以知道要想两个时间同时发生假设事件A发生的概率为p(A),b发生的概率为p(b),则两事件同时发生的概率为p(A)*p(b);
所以我们得到状态方程为
dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]*w[j]);//需要解释一下这个地方,
我们需要找出本题的背包容量
本题还有一个重要的地方就是要注意精度问题,float;
补充一下 0 1背包的概念就是当前事件的决策,做还是不做。
一般的0 1背包问题的状态方程为dp[i]=max(dp[i],dp[i-m[i]]);
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#define max(a,b) (a>b?a:b)
using namespace std;
int main()
{
int t,i,j,n,m[110];
float P,p[110],dp[10010];
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
int sum=0;
cin>>P>>n;
P=1-P;
for(i=1;i<=n;i++)
{
cin>>m[i]>>p[i];
sum+=m[i];
p[i]=1-p[i];
}
dp[0]=1;
for(i=1;i<=n;i++)
{
for(j=sum;j>=m[i];j--)
{
dp[j]=max(dp[j],dp[j-m[i]]*p[i]);
}
}
for(i=sum;i>=0;i--)
{
if(dp[i]>=P)
{
break;
}
}
cout<<i<<endl;
}
return 0;
}
最大报销额
又一个背包问题,对于每张发票,要么报销,要么不报销,0-1背包,张数即为背包;
转移方程:f[j]=max(f[j],f[j-1]+v[i]);
恶心地方:有这样的输入数据 3 A:100 A:200 A:300点击打开链接
最大连续子序列 点击打开链接
无力再吐槽我的编码能力有多弱了,真伤不起啊,一样的公式,只是加了一些限制条件,而且关键就是杭电上的测试样例给的很清楚了。
上我的代码吧:
#include<iostream>
#include<cstring>
#define max(a,b) a>b?a:b
using namespace std;
int main(int i)
{
int t,ans,step=1;
int start,end,k;
int n,data[100001],sum[100001];
//cin>>t;
//while(t--)
//{
while(cin>>n&&n)
{
int out=0;
end=start=k=1;
ans=0;
for(i=1;i<=n;i++)
cin>>data[i];
for(i=1;i<=n;i++)
{
sum[i]=max(sum[i-1]+data[i],data[i]);
if(sum[i]>ans||(sum[i]>=ans&&sum[i]==0))
{
ans=sum[i];
start=k;
end=i;
}
if(sum[i]<0)
{
sum[i]=0;
k=i+1;
}
}
for(i=1;i<=n;i++)
{
if(data[i]>=0)
out=1;
}
if(!out)
{
start=1;
end=n;
}
//if(step!=1)
// cout<<endl;
// cout<<"Case "<<step<<":"<<endl;
cout<<ans<<" "<<data[start]<<" "<<data[end]<<endl;
//step++;
}
return 0;
}
状态方程:sum[i]=max(sum[i-1]+a[i],a[i]);最后从头到尾扫一边
也可以写成:
Max=a[0];
Current=0; for(i=0;i<n;i++)
{ if(Current<0)
Current=a[i]; else
Current+=a[i]; if(Current>Max)
Max=Current;
}
max sum 点击打开链接
我先用不是动态规划的方法给个代码:
#include<iostream>
using namespace std;
int main(int i)
{
int t,sum,k,step=1;
int start,end;
int data[100000],n,m;
cin>>t;
while(t--)
{
k=1;
int max=-99999;
sum=0;
cin>>n;
for(i=1;i<=n;i++)
cin>>data[i];
for(i=1;i<=n;i++)
{
sum+=data[i];
if(max<sum)
{
max=sum;
start=k;
end=i;
}
if(sum<0)
{
sum=0;
k