Knapsack in a Globalized World

Problem description
Globalization stops at nothing, not even at the good old honest profession of a burglar. Nowadays it is not enough to break in somewhere, take everything you can carry and dart off. No! You have to be competitive, optimize your profit and utilize synergies.
So, the new game rules are:
break only into huge stores, so there is practically endless supply of any kind of items;
your knapsack should be huge;
your knapsack should be full (there should be no empty space left).
Damn you, globalization, these rules are not easy to follow! Luckily, you can write a program, which will help you decide whether you should loot a store or not.

Input
The input consists of:
one line with two integers n (1 ≤ n ≤ 20) and k (1 ≤ k ≤ 1018), where n is the number of different item types and k is the size of your knapsack;
one line with n integers g1.... gn (1 ≤ gi ≤ 103 for all 1 ≤ i ≤ n), where g1.... gn are the sizes of the n item types.
Output
Output “possible” if it is possible to fill your knapsack with items from the store (you may assume that there are enough items of any type), otherwise output
Sample Input
Sample Input 1 
2 10000000000
3 6

Sample Input 2 
2 10000000000
4 6
Sample Output
Sample Output 1
impossible

Sample Output 2
possible
Problem Source
GCPC 2016

學長的思路:對於n個數能否構成值K,我們考慮集合S'表示這n個數能構成的數的集合,顯然存在如果一個數x屬於S'那麼x+a[i],x+2*a[i]也屬於集合S',那麼我們定義dp[i]爲%a[1]==i的時候S'中最小的數,那麼所有比dp[i]大的同餘類都一定屬於S',而比dp[i]小的同餘類一定不屬於S',因此可以得到最短路模型,用dp[now]+a[i]更新dp[(dp[now]+a[i])%a[1]];跑一遍最短路即可得到所有dp[i] (i的取值範圍<a[1]),所以最好先sort一下,讓a[1]最小。最後判別k是不是大於等於dp[k%a[1]]就可以,複雜度很優秀,spfa大概78ms過。

#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
ll sum,dp[1005];
int n,a[30];
bool vis[1005];
queue<int> q;
void spfa(){
    memset(dp,0x3f,sizeof(dp));
    dp[0]=0;
    q.push(0);
    while(!q.empty()){
        int cur=q.front();q.pop();vis[cur]=0;
        for(int i=1;i<n;i++)
        if(dp[(cur+a[i])%a[0]]>dp[cur]+a[i]){
            dp[(cur+a[i])%a[0]]=dp[cur]+a[i];
            if(!vis[(cur+a[i])%a[0]]) vis[(cur+a[i])%a[0]]=1,q.push((cur+a[i])%a[0]);
        }
    }
}
int main(){
    scanf("%d%I64d",&n,&sum);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    sort(a,a+n);
    spfa();
   // printf("%I64d\n",dp[sum%a[0]]);
    if(sum>=dp[sum%a[0]]) printf("possible\n");
    else                  printf("impossible\n");
}



#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,a[30],dp[1000005];
ll sum;
ll gcd(ll a,ll b){
      return b==0?a:gcd(b,a%b);
}
bool solve(){
     if(sum>a[n-1]*a[n-1]){
        ll d=a[0];
        for(int i=1;i<n;i++) d=gcd(d,a[i]);
        if(sum%d==0) return true;
        else         return false;
     }
     dp[sum]=1;
     for(int i=0;i<n;i++)
         for(int j=(int)sum;j>0;j--){
              if(dp[j]&&j-a[i]>=0) dp[j-a[i]]=1;   
         }
     if(dp[0]) return true;
     return false;
}
int main(){
    scanf("%d%I64d",&n,&sum);
    for(int i=0;i<n;i++) scanf("%I64d",&a[i]);
    sort(a,a+n);
    if(solve()) printf("possible\n");
    else        printf("impossible\n");
   // cin>>n;
}



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