加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

GKnapSack(跳跃点法解 0-1 背包问题)

(2015-10-08 14:49:52)
标签:

it

动规

分类: ACM
对于 0-1 背包问题,DP的解法很普遍。还有一种“跳跃点”的解法,该方法的提出,是根据背包求解过程中的记录表 v(i,j)的函数性特点而来的。(v(i,j)表记录的是前 i 种物品,达到总重量 j 时的最大利益)
可以Dp 求解一下,然后打印一下表进行观察,也可以根据这个求解原理,可以很自然的想到,v(i,j)的函值, 当 i 确定时,这是一个关于 j 的非递减函数,且由“跳跃点”将函数分段儿了,类似于上取整/下取整的函数图像,以跳跃点为分界非递减的一段一段儿“平”的函数图像。在求解过程中,每一个 i 都会有对应着一个这样的函数图像,并且最后一个求解时,刚好,最高的跳跃点对应的函数线即为解。
根据 v(i,j) = max(v(i-1,j) , v(i-1,j-w[i])+v[i]),即对于一个函数图像 v(i)是可以有其“前驱” v(i-1)得出的。求解过程是 由前导后的,并且根据公式,本质上,新的跳跃点,新的函数图像就是在已有图像的基础上得出的(即 i 状态本身就是在 i-1 的状态下得出的)。实际求解过程 :(过程中需要打表记录,表中的数据记录是一个structure,即占用 w 时最大价值为 v,过程中以 i (前 i 种物品为状态标记量))
1.初始化 p(0)<0 , 0 >   // 边界
2.由 p(i-1)[ v ( i -1 , j ) 的状态图 ] 得到 q(i-1)[ v ( i - 1 , j - w[i] ) + v[i] 的状态图 ] . 只需要在 p(i-1)的基础上 + (wi,vi)得到新的跳跃点即可。
3. p(i-1)并上 q(i-1)在减去必然不合法的点(同 w 下 v 非最大的点)即为 p(i)
上述即为求解过程,迭代实现即可。
代码在实际实现的过程中,把一维表 table 用作了 二维表,通过 head[ ] 数组的划分,达到了二维表的效果,head[ i ] 表示 p(i)在表中的首元素位置。同时借助 p(i-1)导 p(i)的时候,用 l ,r 作为指针,卡在了p(i-1)的左右作为边界,next是p(i)要填写的位置,最初时 next 为 p(i)的head 位置。
先在 p(i-1)的元素 j 上得到一个新状态,然后 w 小于它的不受影响,直接搬,w 等于它的,对 v 取大更,w 大于它的,根据 v 值直接pass 掉 不合法的点(w 大但 v 小于前边的),同时,出现了新状态往里写的时候,也要注意,w 大 v 也大时才合法,才可以往里写,反之直接扔掉。(在跳跃点函数图像中,保留的的是 max ,即p(i-1),q(i-1)俩函数图取 max 的合图)
记录好表之后,从终态开始往回倒找解路径即可。

示例代码 :

#include
#include
#include
#include
#include

using namespace std;

const int N = 1e4 , M = 1e6;

struct Data
{
    int w , v;
    Data(int nw = 0 , int nv = 0):w(nw) , v(nv){}
    Data operator +(const Data& r)const
    {
        return Data(w+r.w , v+r.v);
    }

    bool operator ==(const Data& r)const
    {
        return (w==r.w) && (v==r.v);
    }
};

int head[N+5];
Data goods[N] , table[M];
stack s;
int n , c;

// trace back to find the solution vector x[1……n]
void traceBack(Data eState)
{
    int i , j;
    bool x[N+2];
    for(i = n ; i >= 1 ; --i)
    {
        x[i] = false;
        for(j = head[i]-1 ; j >= head[i-1] ; --j)
        {
            if(table[j]+goods[i] == eState && (table[j].w != 0 || !j))
            {
                s.push(i);
                eState = table[j];
                break;
            }
        }
    }
}

// jump points' method to slove the 0-1 bag's problem
int GKnapSack()
{
    int i , k , j , l , r , next;
    Data temp;

    head[0] = 0;
    table[0] = Data(0 , 0);
    l = r = 0;
    next = 1;
    head[1] = 1;
    for(i = 1 ; i <= n ; ++i)
    {
        k = l;
        for(j = l ; j <= r ; ++j)
        {
            if(table[j].w+goods[i].w > c)
                break;
            temp = table[j]+goods[i];
            while(k<=r && table[k].w
            {
                table[next] = table[k];
                ++next;
                ++k;
            }
            if(k<=r && table[k].w==temp.w)
            {
                temp.v = max(temp.v , table[k].v);
                ++k;
            }
            if(temp.v > table[next-1].v)
            {
                table[next] = temp;
                ++next;
            }
            while(k<=r && table[k].v<=table[next-1].v)
                ++k;
        }
        while(k <= r)
        {
            table[next] = table[k];
            ++next;
            ++k;
        }

        l = r+1;
        r = next-1;
        head[i+1] = next;
    }

    traceBack(table[next-1]);

    return table[next-1].v;
}

int main()
{
    int i;

    scanf("%d%d" , &n , &c);
    // the number of goods and the capcity of the bag

    for(i = 1 ; i <= n ; ++i)
    {
        scanf("%d%d" , &goods[i].w , &goods[i].v);
        // the weight and the value of goods i
    }

    printf("\n%d\n" , GKnapSack());

    for(i = 0 ; i <= n ; ++i)
    {
        printf("%d : " , i);
        for(int j = head[i] ; j < head[i+1] ; ++j)
        {
            printf("%d %d ; " , table[j].w , table[j].v);
        }
        printf("\n");
    }

    printf("\n");
    while(!s.empty())
    {
        printf("%d " , s.top());
        s.pop();
    }
    printf("\n");

    return 0;
}



0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有