关于初始化:
在求最优解的背包问题中,一般有两种不同的问法:1、要求“恰好装满背包”时的最优解;2、求小于等于背包容量的最优解,即不一定恰好装满背包。
这两种问法,主要区别是在初始化的时候。
a: 要求“恰好装满背包”时的最优解:
在初始化时除了F[i][0]为0其它F[i][j]均设为-∞,这样就可以保证最终得到的s是一种恰好装满背包的最优解。如果不能恰好满足背包容量,即不能得到s的最优值,则此时s=-∞,这样就能表示没有找到恰好满足背包容量的最优值。
b: 求小于等于背包容量的最优解,即不一定恰好装满背包:
如果并没有要求必须把背包装满,而是只希望价值尽量大,初始化时应该将F[i][j]全部初始化为0。
F[1][2]=max(F[0][2],F[0][2-2]+v[1]) 可以得到一个正数
=max(F[0][2],F[0][0]+v[1])=f[0][0]+v[1] 【F[0][j]=-oo,F[0][0]=0】
F[1][3]=max(F[0][3],F[0][3-2]+v[1]) 结果是负数
=max(F[0][3],F[0][1]+v[1])=F[0][1]+v[1]=-oo 【F[0][j]=-oo,F[0][1]=-oo】
2、解析:
因为只有F[i][0]=0,若在每一步恰好装满,例:
求F[1][2]要求不一定恰好装满背包,求F[1][3]要求恰好装满背包
F[1][2]=max(F[0][2],F[0][2-2]+v[1]) 可以得到一个正数
=max(F[0][2],F[0][0]+v[1])=f[0][0]+v[1] 【F[0][j]=-oo,F[0][0]=0】
F[1][3]=max(F[0][3],F[0][3-2]+v[1]) 结果是负数
=max(F[0][3],F[0][1]+v[1])=F[0][1]+v[1]=-oo 【F[0][j]=-oo,F[0][1]=-oo】
01背包:
for i=1..N
for v=V..0
f[v]=max{f[v],f[v-c[i]]+w[i]};
完全背包:
for i=1..N
for v=0..V
f[v]=max{f[v],f[v-cost]+weight}
混合背包:
for i=1..N
if 第i件物品是01背包
ZeroOnePack(c[i],w[i])
else if 第i件物品是完全背包
CompletePack(c[i],w[i])
else if 第i件物品是多重背包
MultiplePack(c[i],w[i],n[i])
二维费用背包:
for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]}
分组背包:
for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]};
poj 3267:The Cow Lexicon
大致题意:
给出一个长度为l的文本和一个由n个单词组成的字典。求至少从文本中去掉多少个字符才能使得这个文本全部由字典中的单词组成。
大致思路:
DP,转移方程为dp[i]=min(dp[i-1]+1,dp[pos+1]+i-pos-1-tmp);//dp[i]为前i个字符中需要去掉的字符数量。
转移的示例如下,这里文本是browndcodw 文本是cow,从str[9]开始匹配~~
b r o w n d c o d w
c o w //找到一个匹配,并需要剔除一个字母。所以dp[10]可以从dp[6]转化而来。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char str[1000];
char word[1000][30];
int dp[1000];
int main(){
int n,len,i,j,pos,k,tmp;
while(scanf("%d%d",&n,&len)!=EOF){
scanf("%s",str);
for(i=0;i<n;i++){
scanf("%s",word[i]);
}
dp[0]=0; //前i个字符中包含的非法字符数量
for(i=1;i<=len;i++){
dp[i]=dp[i-1]+1;
for(j=0;j<n;j++){
tmp=k=strlen(word[j]);
k-=1;
pos=i-1;
while(pos>=0&&k>=0){
if(str[pos]==word[j][k]){
k--;
}
pos--;
}
if(k<0){ //可以匹配出一个单词
dp[i]=min(dp[i],dp[pos+1]+i-pos-1-tmp);
}
}
}
printf("%d\n",dp[len]);
}
return 0;
}
#include <iostream>
using namespace std;
const int N = 100;
int a[N], dp[N], n;
int lis(int n)
{
int res = 0;
for(int i=0; i<n; i++) {
dp[i] = 1;
for(int j=0; j<i; j++)
if(a[j] < a[i])
dp[i] = max(dp[i], dp[j] + 1);
res = max(res, dp[i]);
}
return res;
} //最长上升子序列
int lds(int n)
{
int res = 0;
for(int i=0; i<n; i++) {
dp[i] = 1;
for(int j=0; j<i; j++)
if(a[j] > a[i])
dp[i] = max(dp[i], dp[j] + 1);
res = max(res, dp[i]);
}
return res;
} //最长下降子序列
int main()
{
char ch;
n = 0;
while(scanf("%d%c", &a[n++], &ch))
if(ch == '\n')
break;
int ans1 = lds(n);
cout << ans1 << "," << lis(n) - 1 << endl;
return 0;
}
最长上升子序列nlogn
int dp[MAX_N];
void solve()
{
fill(dp,dp+n,INF);
for(int i = 0;i < n;i++)
{
*lower_bound(dp,dp+n,a[i]) = a[i];
}
printf("%d\n",lower_bound(dp,dp+n,INF)-dp);
}