动态规划2

A - Max Sum Plus Plus[排列组合]

这个真的很难搞,排列组合也太难了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e6+10;
const int INF = 0x7fffffff;
int a[maxn];
int dp[maxn];
int Max[maxn];//max(dp[i-1][k])就是上一组0~j-1的最大值
int main(){
    int n,m,mmax;
    while(~scanf("%d%d",&m,&n))
    {
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
        }
        memset(dp,0,sizeof(dp));
        memset(Max,0,sizeof(Max));//分成0组的全是0
        for(int i = 1; i <= m; i++)
        {//分成i组
            mmax = -INF;
            for(int j = i; j <= n; j++)
            {//前j个数分成i组,至少需要i个数
                dp[j] = max(dp[j-1]+a[j],Max[j-1]+a[j]);
                //Max[j-1]目前代表的是分成i-1组前j-1个数的最大值,a[j]单独一组组成i组
                //dp[j-1]代表j-1个数分成组,第j个数a[j]放在前面i组的一组中,两种方式选取较大者
                Max[j-1] = mmax;//当前考虑的是j但是mmax是上一次循环得到的,所以更新的是j-1
                mmax = max(mmax,dp[j]);//更新mmax,这样下次循环同样更新的是j-1
            }
            //这样也就更新得到了分i组的Max,下次分i+1组的时候就可以使用了
        }
        printf("%d\n",mmax);
    }
    return 0;
}

B - Robot[概率]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e6+10;
int n,m,l,r,w;
double dp[maxn],db[maxn];
int main(){

    int n,m,mmax;
    while(~scanf("%d%d%d%d",&n,&m,&l,&r)&&(n||m||l||r))
    {
        db[0]=1;
        for(int i = 1; i <= m; i++)
        {
            scanf("%d",&w);
            for(int j=0;j<n;++j)
            {
                if(db[j]>0)//剪枝
                {
                    dp[(j+w+n)%n] += db[j]*0.5; //向前跳w步
                    dp[(j-w+n)%n] += db[j]*0.5; //向后跳w步
                }
            }

            memcpy(db,dp,sizeof(double)*n);
            memset(dp,0,sizeof(double)*n);
        }
        double re=0;l--,r--;
        for(int i=l;i<=r;++i) re+=db[i];
        printf("%.4f\n",re);
        memset(db,0,sizeof(dp));
        memset(db,0,sizeof(db));
    }
    return 0;
}

C - Happy Matt Friends[01背包+滚动数组]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX= 1<<20;
int dp[2][MAX],a[44];
int main()
{
    int T,N,M;scanf("%d",&T);
    for(int t=1;t<=T;++t)
    {
        scanf("%d%d",&N,&M);
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i = 1; i <= N; i++)
            scanf("%d",&a[i]);
            
        for(int i=1;i<=N;++i)
            for(int j=0;j<MAX;++j)
                dp[i&1][j] = dp[(i-1)&1][j]+dp[(i-1)&1][j^a[i]];
                
        long long re=0;
        int n=N&1;
        for(int i=M;i<MAX;++i)
        {
            re+=dp[n][i];
        }
        printf("Case #%d: %I64d\n",t,re);
    }
    return 0;
}

D - 最大报销额[01背包]

背包类型变成float型了,可以先放大后缩小来变成整形

#include<iostream>
#include<string.h>
#include<map>
#include<stdio.h>
#define MAX 3000010
using namespace std;
int dp[MAX],bill[MAX];
double q,temp[4];
int N,ii,m;
void Copy(double temp[])
{
    int flag=1;double sum=0;
    for(int i=0;i<3;++i)
    {
        if(temp[i]>600){flag=0;break;}
        sum+=temp[i];
    }
    if(sum>1000)flag=0;
    if(flag)
    {
        bill[ii++]=(int)(sum*100);
    }
}
int main()
{
    while(~scanf("%lf %d",&q,&N))
    {
        if(N==0) break;
        int Q=(int)(q*100);//double化整形
        memset(bill,0,sizeof(bill));ii=0;

        for(int nn=0;nn<N;++nn)//输入N个账单
        {
            scanf("%d",&m);getchar();
            memset(temp,0,sizeof(temp));int flag=1;
            for(int i=0;i<m;++i)//输入账单中的每个物品
            {
                char t;double v;
                scanf("%c:%lf",&t,&v);  getchar();
                if('A'<=t&&t<='C'){ temp[t-'A']+=v;}
                else { flag=0; }
            }
            if(flag)Copy(temp);//保存合法的账单
        }
        memset(dp,0,sizeof(dp));
        for(int i=0;i<ii;++i)
        {
            for(int j=Q;j>=bill[i];j--)
            {
                dp[j]=max(dp[j],dp[j-bill[i]]+bill[i]);
            }
        }
        printf("%.2lf\n",dp[Q]/100.0);
    }
    return 0;
}

E - FATE[二维完全背包]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX= 1<<20;
int dp[101][101];
struct a
{
    int v,e;
}a[101];
int n,m,k,s;
void f()
{
    cout<<">>";
        for(int i=1;i<=m;++i)
        {
            cout<<dp[i]<<" ";
        }cout<<endl;
}
int main()
{
    int j,i,t;
    while(~scanf("%d%d%d%d",&n,&m,&k,&s))
    {

        for(int y = 1; y <= k; y++)
            scanf("%d%d",&a[y].v,&a[y].e);
        memset(dp,0,sizeof(dp));
        for(i=1;i<=k;++i)
            for(j=a[i].e;j<=m;++j)
                for(t=1;t<=s;++t)
                    if(dp[j][t]<(dp[j-a[i].e][t-1]+a[i].v))
                    {
                         dp[j][t] = dp[j-a[i].e][t-1]+a[i].v;
                    }
        if(dp[m][s]>=n)
        {
            for(int h=0;h<=m;++h)
            {
                if(dp[h][s]>=n)
                {
                    printf("%d\n",m-h);break;
                }
            }
        }
        else
            printf("-1\n");
    }
    return 0;
}

F - Coins[多重背包+完全背包+01背包+二进制优化]

#include <stdio.h>
 
#include <iostream>
#include <algorithm>
#include <cstring>
#define MAX 1000000
using namespace std;
int dp[MAX];//存储最后背包最大能存多少
int value[MAX],weight[MAX],number[MAX];//分别存的是物品的价值,每一个的重量以及数量
int bag;
void ZeroOnePack(int weight,int value )//01背包
{
    int i;
    for(i = bag; i>=weight; i--)
    {
        dp[i] = max(dp[i],dp[i-weight]+value);
    }
}
void CompletePack(int weight,int value)//完全背包
{
    int i;
    for(i = weight; i<=bag; i++)
    {
        dp[i] = max(dp[i],dp[i-weight]+value);
    }
}
 
void MultiplePack(int weight,int value,int number)//多重背包
{
    if(bag<=number*weight)//如果总容量比这个物品的容量要小,那么这个物品可以直到取完,相当于完全背包
    {
        CompletePack(weight,value);
 
    }
    else//否则就将多重背包转化为01背包
    {
        int k = 1;
        while(k<=number)
        {
            ZeroOnePack(k*weight,k*value);
            number = number-k;
            k = 2*k;//这里采用二进制思想
        }
        ZeroOnePack(number*weight,number*value);
    }
}
int main()
{
    int n;
    while(~scanf("%d%d",&n,&bag))
    {
        if(n==0&&bag==0)
            break;
        int i,sum=0;
        for(i = 0; i<n; i++)
            scanf("%d",&value[i]);//输入价值
        for(i=0;i<n;i++)
            scanf("%d",&number[i]);//输入数量  此题没有物品的重量,可以理解为体积和价值相等
        memset(dp,0,sizeof(dp));
        for(i = 0; i<n; i++)
        {
            MultiplePack(value[i],value[i],number[i]);//调用多重背包,注意穿参的时候分别是重量,价值和数量
        }
        int ans=0;
        for(i=1;i<=bag;i++)
        {
            if(i==dp[i])
                ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

G - Robberies[01背包]

稍微要绕一下,被抓的概率要改成不被抓的概率,每偷一个不被抓的概率都会下降,要用乘法而不是加法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX= 1e4+3;
double dp[MAX];
struct
{
    int m;
    double p;
}bank[MAX];
int N,T,S;
double q,temp;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
       scanf("%lf%d",&q,&N);S=0;q=1-q;
       for(int i=1;i<=N;++i)
       {
            scanf("%d%lf",&bank[i].m,&bank[i].p);
            bank[i].p=1-bank[i].p;//转化为不被抓的概率
            S+=bank[i].m;
       }
       memset(dp,0,sizeof(dp));dp[0]=1;
       for(int i=1;i<=N;++i)
            for(int j=S;j>=bank[i].m;--j)
                dp[j]=max(dp[j],dp[j-bank[i].m]*bank[i].p);
       int re=0;
       for(int j=S;j>=0;--j)
       {
           if(!(dp[j]<q))
           {
               printf("%d\n",j);
               break;
           }
       }
    }
    return 0;
}

H - Max Sum[01背包]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX= 1e5+5;
int dp[MAX];
int k[MAX];
int N,T;
int main()
{
    scanf("%d",&T);
    int re=0,l,j,r;
    for(int tt=1;tt<=T;++tt)
    {
       scanf("%d",&N);
       for(int i=1;i<=N;++i) scanf("%d",&k[i]);
       memset(dp,0,sizeof(dp));
       l=r=j=1,re=k[1];dp[1]=k[1];
       for(int i=2;i<=N;i++)
		{
			if(dp[i-1]+k[i]>=k[i])
			{
				dp[i]=dp[i-1]+k[i];
			}
			else
			{
				dp[i]=k[i];
				j=i;
			}
			if(dp[i]>re)
			{
				re=dp[i];
				l=j;
				r=i;
			}
		}
		printf("Case %d:\n%d %d %d\n",tt,re,l,r);
		if(tt!=T)
            printf("\n");
    }
    return 0;
}

I - Super Jumping! Jumping! Jumping![010背包]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX = 1002;
int k[MAX],dp[MAX];
int N,T;
int main()
{
    while(~scanf("%d",&T)&&T)
    {
        memset(k,0,sizeof(k));
        for(int i=1;i<=T;++i) scanf("%d",&k[i]);
        for(int i=1;i<=T;++i)
        {
            int big=0;
            for(int j=1;j<i;++j)
              if(k[j]<k[i])
                   big=max(big,dp[j]);
            dp[i]=big+k[i];
        }
        int ans=-1;
        for(int i=1;i<=T;++i)
            ans=max(ans,dp[i]);
        cout<<ans<<endl;
    }
    return 0;
}

J - Calling Extraterrestrial Intelligence Again[完全不知道哪里跟dp有关]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX = 1e5+5;
int k[MAX],dp[MAX];
int N,T;
int prim[MAX] = {1}, s[MAX],l=0;
int m,a,b,p,q;
void prime()
{
	int i, j;
	memset(prim, 0, sizeof(prim));
	for (i = 2; i < MAX; i++)
	{
		if (prim[i])continue;
		for (j = i + i; j < MAX; j += i)
		{
			prim[j] = 1;
		}
		s[l++] = i;
	}
	//s里面保存的是2-MAX的素数
}
bool Check_p(int x,int y)
{
    return (prim[x]==0)&&(prim[y]==0);
}
bool Check_f(int x,int y)
{
    return a*y>x*b;
}
struct V
{
    int pp,qq,mm;
}big;
int main()
{
    prime();
    while(~scanf("%d%d%d",&m,&a,&b)&&(m||a||b))
    {
       int End=(int)sqrt(m);
       big.mm=big.pp=big.qq=0;
       for(int i=0;s[i]<=End;++i)
       {
          p=s[i];q=m/s[i];
          while(prim[q]||Check_f(p,q)) q--;
         // printf("%d %d %d\n",p,q,s[i]);
          if(big.mm<p*q)
          {
              big.mm=p*q;
              big.pp=p;
              big.qq=q;
          }
        }
        printf("%d %d\n",big.pp,big.qq);
    }
    return 0;
}

  

posted @ 2020-03-09 15:43  东坡肉肉君  阅读(186)  评论(0编辑  收藏  举报