做了下背包的题
题目:给出两个数n,m。m代表求出的n的划分中最大值不能超过m。比如n=5,m=3。则用1,2,3这三个数去分割5。求方案数。
f(n,m)代表求不超过m的n的划分数。
f(n,m)=1;n=1或m=1
f(n,m)=f(n,n);n<m
f(n,m)=f(n,m-1);n==m
f(n,m)=f(n-m,m)+f(n,m-1);n>m选m或不选m
这个题n的范围是1000,m的范围是100,最后求出的划分数明显大于10^18,所以这里需要修改一下状态转移方程。
状态转移方程:a[n]+=a[n-m]; a[n]%=INF;求10^18前面的数。
b[j]+=b[j-i]+(a[j]+a[j-i])/INF;求10^18后面的数。最后如果划分数大于INF,结果为两者之和,否则为a[n]。
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include<cstring>
#define ll 0x3f3f3f
using namespace std;
long long INF,a[1010],b[1010];
int main()
{
int n,k;
INF=1;
for(int i=0; i<18; i++)
INF*=10;
cin>>n>>k;
memset(b,0,sizeof(b));
memset(a,0,sizeof(a));
a[0]=1;
for(int i=1; i<=k; i++)
{
for(int j=i; j<=n; j++)
{
b[j]+=b[j-i]+(a[j]+a[j-i])/INF;
a[j]+=a[j-i];
a[j]%=INF;
}
}
if(b[n])
cout<<b[n];
cout<<a[n]<<endl;
return 0;
}
道路
W 国的交通呈一棵树的形状。W 国一共有n - 1n−1个城市和nn个乡村,其中城市从11到n - 1n−1 编号,乡村从11到nn编号,且11号城市是首都。道路都是单向的,本题中我们只考虑从乡村通往首都的道路网络。对于每一个城市,恰有一条公路和一条铁路通向这座城市。对于城市i, 通向该城市的道路(公路或铁路)的起点,要么是一个乡村,要么是一个编号比ii大的城市。 没有道路通向任何乡村。除了首都以外,从任何城市或乡村出发只有一条道路;首都没有往 外的道路。从任何乡村出发,沿着唯一往外的道路走,总可以到达首都。
W 国的国王小 W 获得了一笔资金,他决定用这笔资金来改善交通。由于资金有限,小 W 只能翻修n - 1n−1条道路。小 W 决定对每个城市翻修恰好一条通向它的道路,即从公路和铁 路中选择一条并进行翻修。小 W 希望从乡村通向城市可以尽可能地便利,于是根据人口调 查的数据,小 W 对每个乡村制定了三个参数,编号为ii的乡村的三个参数是a_iai,b_ibi和c_ici。假设 从编号为ii的乡村走到首都一共需要经过xx条未翻修的公路与yy条未翻修的铁路,那么该乡村 的不便利值为
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
int n;
struct node{LL x,y,z;} a[20010];
int son[20010][5];
LL f[20010][45][45];
LL dfs(int x,int p,int q)
{
if(x>=n) return a[x-n+1].z*(a[x-n+1].x+p)*(a[x-n+1].y+q);
if(f[x][p][q]!=f[n+1][41][41]) return f[x][p][q];
return f[x][p][q]=min(dfs(son[x][0],p,q)+dfs(son[x][1],p,q+1),dfs(son[x][1],p,q)+dfs(son[x][0],p+1,q));
}
int main()
{
int x,y;
scanf("%d",&n);
memset(f,63,sizeof(f));
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
if(x<0) x=-x+n-1;
if(y<0) y=-y+n-1;
son[i][0]=x;
son[i][1]=y;
}
for(int i=1;i<=n;i++)
scanf("%lld %lld %lld",&a[i].x,&a[i].y,&a[i].z);
printf("%lld",dfs(1,0,0));
}
解析看的题解:
直接考虑树形DP
设f [ u ] [ i ] [ j ] f[u][i][j]f[u][i][j]为从根节点到u节点经过了i条没经过标记的L边和j条没经过标记的R边
对于每个叶子节点直接枚举最佳答案
f [ u ] [ j ] [ j ] = c u ( a u + i ) ( b u + j ) f[u][j][j]=c_u(a_u+i)(b_u+j)
f[u][j][j]=c u (a u +i)(b u +j)
对于每个非叶子节点枚举左右删去哪条边
f [ u ] [ i ] [ j ] = m i n { f [ l s o n ] [ i + 1 ] [ j ] + f [ r s o n ] [ i ] [ j ] , f [ l s o n ] [ i ] [ j ] + f [ r s o n ] [ i ] [ j + 1 ] } f[u][i][j]=min{ f[lson][i+1][j]+f[rson][i][j],f[lson][i][j]+f[rson][i][j+1]}
f[u][i][j]=min{f[lson][i+1][j]+f[rson][i][j],f[lson][i][j]+f[rson][i][j+1]}
馒头:
有 M 种互不相同的馒头各一个,第 i 个馒头卖 Pi元。
有 N 个包装盒,第 j 个包装盒最多能装 Ci 个馒头,买第 j 个包装盒的花费为 Ej 元。要求只能将一些馒头放进包装盒中打包出售,不能零售,当然也可以不出售某些馒头(卖剩的馒头被出题人吃了,出题人还吃得津津有味~)。售出一盒馒头得到的利润为盒内所有馒头的价格减去包装盒的价格。
现在买下(这 N 个包装盒)其中的一些包装盒(也可以不买,还可以全买),将馒头打包出售,求最大可能利润。
#include<bits/stdc++.h>
using namespace std;
int n,m,a[10010],anss,dp[510][10010];
struct node{
int c,e;
}b[510];
int cmp(int x,int y) {return x>y;}
int main()
{
scanf("%d%d",&m,&n);
for (int i=1;i<=m;i++) scanf("%d",&a[i]);
sort(a+1,a+1+m,cmp);
for (int i=1;i<=m;i++) a[i]+=a[i-1];
for (int i=1;i<=n;i++) scanf("%d%d",&b[i].c,&b[i].e);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (j<=b[i].c) dp[i][j]=max(dp[i-1][j],a[j]-b[i].e);
else dp[i][j]=max(dp[i-1][j],dp[i-1][j-b[i].c]+a[j]-a[j-b[i].c]-b[i].e);
anss=max(anss,dp[i][j]);
}
cout<<anss<<endl;
return 0;
}
比较简单的背包题,能独立做出来
总结:简单的能直接做出来,难的看下思路 能自己写出状态转移方程,比以前有很大进步