背包

1 篇文章 0 订阅

关于初始化:

在求最优解的背包问题中,一般有两种不同的问法: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);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值