动态规划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;
}

浙公网安备 33010602011771号