POJ 1014 Dividing

題目大意:有六種等級的石頭,已知每個等級石頭的個數,求是否存在一種方案,使這些石頭能分成兩堆,滿足這兩堆石頭的等級之和相等。

思路:一開始想要進行DFS,不過題目給出石頭總數最大會達到20000,所以DFS顯然會超時。可以對問題稍微轉化一下,首先求出石頭的價值總和,如果是奇數顯然沒有方案。如果是偶數則除以2,記結果爲capacity,然後對等級爲i的石頭視爲體積爲i,價值爲i的物品,並儘量填滿capacity;令dp[i]表示體積爲i的容器所裝載的最大價值,如果dp[v]==v則說明存在方案,否則不存在。

    這樣就把問題轉化爲多重揹包問題。多重揹包問題存在兩種情況:

(1)當n[i]*i>=capacity時,則視爲完全揹包問題,僞代碼爲:

 

for j = i to capacity
    dp[j] = max (dp[j], dp[j-i]+i)


(2)當n[i]*i<capacity時,將石頭分解,視爲01揹包問題,僞代碼爲:

integer:k=1,amount=n[i];
while k<amount
begin
    for j = capacity to i*k
        dp[j] = max (dp[j], dp[j-k*i]+k*i)
    amount = amount - k;
    k = k * 2;
end;
for j = capacity to i*amount
    dp[j] = max(dp[j], dp[j-amount*i]+amount*i);


 

代碼:

#include <iostream>

using namespace std;

int n[7],sum_value,capacity,amount;
int dp[120005];

inline int max2(int a,int b)
{
    if (a>b)
        return a;
    return b;
}

int main()
{
    int i,j,k,test_cases=1;
    while (scanf("%d%d%d%d%d%d",&n[1],&n[2],&n[3],&n[4],&n[5],&n[6])==6)
    {
        for (i=1,sum_value=0;i<=6;i++)
            sum_value+=n[i]*i;
        if (sum_value==0)
            break;
        if (sum_value%2!=0)
        {
            printf("Collection #%d:\n",test_cases++);
            printf("Can't be divided.\n\n");
            continue;
        }
        capacity=sum_value/2;
        memset(dp,0,sizeof(dp));
        for (i=1;i<=6;i++)
        {
            if (n[i]*i>=capacity)
                for (j=i;j<=capacity;j++)
                    dp[j]=max2(dp[j],dp[j-i]+i);
            else
            {
                k=1;
                amount=n[i];
                while (k<amount)
                {
                    for (j=capacity;j>=i*k;j--)
                        dp[j]=max2(dp[j],dp[j-k*i]+k*i);
                    amount-=k;
                    k*=2;
                }
                for (j=capacity;j>=i*amount;j--)
                    dp[j]=max2(dp[j],dp[j-amount*i]+amount*i);
            }
        }
        printf("Collection #%d:\n",test_cases++);
        if (dp[capacity]==capacity)
            printf("Can be divided.\n\n");
        else
            printf("Can't be divided.\n\n");
    }
    return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章