Bottle Taps

1326. Bottle Taps

Time limit: 3.0 second
Memory limit: 64 MB
Programmer Petrov has a hobby to collect beer-bottle taps. There’s nothing unusual — he knows hundreds of programmers that like beer. And they collect taps, too. Not everyone, but some of them.
Frankly speaking, he has bought a part of his collection. But unfortunately he hasn’t got some rare taps to complete his collection. He has found some programmers over the Internet that are ready to sell him these taps. Some of the programmers sell the taps in sets with big discounts.
It’s left to find an optimal offer. Petrov can explain to his wife why he is to store the taps but he won’t be able to prove why he is to spend money for the collection. So he is to buy the taps as cheap as possible.
Petrov has written down all the variants and has started thinking. There’s no way to find out the solution of the problem without a program!

Input

The first line contains an integer N, an amount of available taps (1 ≤ N ≤ 20). The following Nlines contain prices of bottles with the taps if one buys them in stores. The next line contains an integer M (0 ≤ M ≤ 100) — an amount of offers to sell the taps. The following M lines describe the sets. The first number of each line is the price of the set and the second one is the amount of taps in the set. Then there are numbers of the taps in the set (each number lies in the range from 1 to N). The numbers in a set are unique. All the prices are positive integers and do not exceed 1000. The last line begins with the amount of taps that Petrov plans to buy. Then their numbers follow separated by spaces. These numbers are unique, too.

Output

Output the minimal sum of money that Petrov should spend on obtaining the necessary taps.

Sample

input output
4
10
11
12
13
3
17 2 1 3
25 3 2 3 4
15 2 3 4
3 1 3 4
25

/**
   題意:收集瓶蓋,首先給出單個收集時,每種瓶蓋的價格;
   然後,給出m種優惠策略,
   再給出收集目標,求最小花費。
   注意:
   比不要恰好收集齊目標,可以收集的比目標多,但收集目標必須完成;
   每種瓶蓋也不一定只收集一個,可以多個;
**/
#include <map>
#include <set>
#include <list>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <vector>
#include <bitset>
#include <cstdio>
#include <string>
#include <numeric>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long  ll;
typedef unsigned long long ull;

int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};//up down left right
bool inmap(int x,int y,int n,int m){if(x<1||x>n||y<1||y>m)return false;return true;}
int hashmap(int x,int y,int m){return (x-1)*m+y;}

#define eps 1e-8
#define inf 0x7fffffff
#define debug puts("BUG")
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define read freopen("in.txt","r",stdin)
#define write freopen("out.txt","w",stdout)
#define maxn 1<<20
/*
http://acm.timus.ru/problem.aspx?space=1&num=1326
*/
struct Node
{
    int w;
    int s;
}node[maxn];

int a[22];
long long dp[maxn];
int n;
int m;
int S;

/*每種至多買一件的價錢*/
void dfs(int s0,int x,int w)//當前狀態s0,當前物品爲x,當前狀態的價格爲w
{
    if(x==n)//表示前面n件已經遍歷完了
    {
        dp[s0]=w;
        return ;
    }
    dfs(s0,x+1,w);            //表示沒買第x件
    dfs(s0|(1<<x),x+1,w+a[x]);//表示買了第x件後,的價值爲p+a[x]
}
/*每種至多買一件的價錢*/
void gao()
{
    int total=(1<<n)-1;
    for(int i=0;i<=total;i++)//easy to understand.
        for(int j=0;j<n;j++)
            if((1<<j)&i)
                dp[i]+=a[j];
}

void DP()
{
    int total=(1<<n)-1;
    long long  ans=inf;
    //dfs(0,0,0);
    gao();//初始化dp,dp初始值是當前狀態沒有任何優惠時的價值
    for(int i=0;i<=total;i++)
    {
        if((i&S)==S)//因爲只要買的狀態包含題目要求的狀態,就可以算作是答案
            ans=min(ans,dp[i]);
        for(int j=0;j<m;j++)
            dp[i|(node[j].s)]=min(dp[i|(node[j].s)],dp[i]+node[j].w);//因爲有優惠,將優惠之後得到的狀態的dp進行更新
    }

    printf("%lld\n",ans);
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);

    scanf("%d",&m);
    for(int i=0;i<m;i++)//保存m種優惠
    {
        int w,j,s0=0;
        scanf("%d%d",&w,&j);
        for(int k=0;k<j;k++)
        {
            int x;
            scanf("%d",&x);
            s0+=(1<<(x-1));
        }
        node[i].w=w;
        node[i].s=s0;
    }

    int j;
    scanf("%d",&j);//用於確定目標狀態
    for(int k=0;k<j;k++)
    {
        int x;
        scanf("%d",&x);
        S+=(1<<(x-1));
    }

    DP();
    return 0;
}


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