多阶图的最短路
对于一个数字矩阵,从左往右走,每次可以直右,右上,右下。走到最后的数字和最小为多少。
同时输出字典序最小的走过的行号。
这里有n^2的状态,但可以容易发现,每一列的n个状态可以划分为一个阶段,实质上是阶段之间的转移。
枚举每个阶段,对于每个阶段的每个状态分别转移即可。
dp[i]][j]表示从i、j开始走到最后的最小和,这是满足最优子结构的。
维护每个状态下一次最优路径的最小行号。(遍历排序即可)。这种链表式的答案,可以保证局部字典序最小,实现全局最小。
[可能你这边比较小,但是答案前面的更小,我从前面的开始是不会经过后面较小的(如果后面较小的前面较大)]。
核心代码:
for(int j=c;j>=1;j--)
for(int i=1;i<=r;i++){
if(j==c)dp[i][j]=A[i][j];
else{
int rows[3]={i,i-1,i+1};
if(i==1)rows[1]=r;
if(i==r)rows[2]=1;
sort(rows,rows+3);
for(int k=0;k<3;k++){
int v=dp[rows[k]][j+1]+A[i][j];
if(v<dp[i][j]){
dp[i][j]=v;ans[i][j]=rows[k];
}
}
}
if(j==1&&dp[i][1]<res){first=i;res=dp[i][1];}
}
printf("%d",first);
for(int i=ans[first][1],j=2;j<=c;i=ans[i][j],j++){
printf(" %d",i);
}
printf("\n%d\n",res);
0-1 背包问题
1、物品无限的背包问题
类似于硬币问题:C->C-V[I]的状态,dp[C]=max(dp[C-V[i]]+W[i]);
2、0-1背包问题
每个物品只能取一次。
所以不能重复遍历了,因为你也不知道哪些已经被选了(状压?数字大的时候没办法状压)
考虑阶段的问题,在把前i个物品放进背包里属于第i个阶段,每个阶段切换到下一个阶段只用判断要不要放新的物品即可。
每个阶段有背包为C以内的状态。dp[i][C]=max(dp[i-1][C-V[i]])。如果我要选择第i个物品,那么对于之前的背包状态必然只有C-V[i].
对内存继续优化,可以考虑滚动数组,因为:状态转移方程算C只会用到C-v[i].那么也就是说,算dp[i][C]的时候,dp[i][C]并没有更新,那么把i去掉,每次计算后面的没更新,还是i-1的阶段。
Jin Ge Jin Qu hao:UVA - 12563
题意:在时间t-1内选择足够多的歌曲,如果有多个选择,选择总歌曲时长最大的。
就是在t-1大的背包里放尽可能多个的歌曲,维护两个背包,一个记录歌曲数量,另一个记录歌曲总时长。
但是背包取优先级是先数量,数量相同的情况再去取总时长更大的。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
#define ll long long
#define M 404
#define inf 0x3f3f3f3f
int T,n,V;
int dp[181*55],pd[181*55];
int main(){
cin>>T;
int cnt=0;
while(T--){
scanf("%d%d",&n,&V);
memset(dp,0,sizeof(dp));
memset(pd,0,sizeof(pd));
for(int i=1;i<=n;i++){
int w;scanf("%d",&w);
for(int j=V-1;j>=0;j--)if(j>=w){
if((dp[j-w]+1>dp[j])||(dp[j-w]+1==dp[j]&&pd[j-w]+w>pd[j])){
dp[j]=dp[j-w]+1;
pd[j]=pd[j-w]+w;
}
}
}
printf("Case %d: %d %d\n",++cnt,dp[V-1]+1,pd[V-1]+678);
}
}
这里突然想到前天训练赛没做出来的一道01背包题目:
题意:有n块砖,已知长和宽,选择一些把宽朝上作为第一层,在第二次把剩下让长朝上。
保证总长度小于第一层,求解让第一层尽可能的短,最短长度。必须用完所有砖。
假如取了1、2作为第一层,3、4、5作为第二层。
a1+a2>=b3+b4+b5;
∑ai-a3-a4-a5>=b3+b4+b5;
∑ai>=a3+b3 + a4+b4 + a5+b5;
必须满足这样的关系,并且使得3、4、5的a3、a4、a5尽可能大,这样的话∑a-a3-a4-a5会尽可能的小。
相等于有n个物品,体积为ai+bi,价值为ai,背包大小为ai的和,往里面 放尽可能多的。