杭电dp题集,附链接还有解题报告!!!!!

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
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值