您的位置:首页 > Web前端

寒假集训——The Fewest Coins

2015-03-10 15:56 337 查看
题目链接

题意:总价钱是T~10000,有n~100种硬币,每个都有一个val~120, 并且我有每种硬币c【i】~10000个,现在给老板一些钱,老板还会找回来一些钱,使得他收到t的钱,使得我给的钱的硬币个数加上老板找回来的硬币个数是最少的,求最少的总个数。老板会用完全背包的最少来找

题解:这题目首先自己是多重背包,用2进制搞就行,老板是完全背包。但是上线怎么确定,就是说我最多给老板多少钱就一定会使他找回来的钱和我多给的是重复的,可以同时去掉。结论是T+MAX_V*MAX_V。证明如下:还没有证明。。。 差这个。搞定之后把部分贪心的那个也弄过来吧————————————

重点:关键是上界的选取,T+MAX_V*MAX_V这个,或者开大一点。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const int maxn = 3e4 + 100;//开大一点
const int key = 3e4;//上限
const int INF = INT_MAX/2 - 1;
int tot, n, val[110], num[110], dp_buy[maxn], dp_change[maxn];

void getDpChange()<span style="font-family: Arial, Helvetica, sans-serif;">//这是完全背包</span>
{
fill(dp_change, dp_change + 1 + key, INF);
//memset(dp_change, -1, sizeof(dp_change));
dp_change[0] = 0;
for(int i = 1;i <= n;i++)
{
for(int j = 0;j <= key;j++)
{
if(j - val[i] >= 0 && dp_change[j - val[i]] >= 0 && dp_change[j - val[i]] + 1 < dp_change[j])
{
dp_change[j] = dp_change[j - val[i]] + 1;
}
}
}
}

void zeroOneP(int n, int v)//cost是v,val是n,01背包的逆序更新
{
for(int j = key;j >= v;j--)
{
dp_buy[j] = min(dp_buy[j], dp_buy[j - v] + n);
}
}
void getDpBuy()//多重背包
{
fill(dp_buy, dp_buy + key + 1, INF);
dp_buy[0] = 0;
for(int i = 1;i <= n;i++)
{
int k = 1;//k先1
while(k < num[i])//小的时候
{
zeroOneP(k, k*val[i]);
num[i] -= k;
k *= 2;
}
zeroOneP(num[i], num[i]*val[i]);//剩下的都弄
}
}
void solve(int m)
{
getDpChange();
getDpBuy();
int ans = INF;
for(int i = m;i <= key;i++)//选取一个个数最少的
{
if(dp_buy[i] < INF && dp_change[i - m] < INF && dp_buy[i] + dp_change[i-m] < ans)
{
ans = dp_buy[i] + dp_change[i-m];
}
}
if(ans >= INF)
{
printf("-1\n");
}
else
{
printf("%d\n", ans);
}
}

int main()
{
//  freopen("8Hin.txt", "r", stdin);
//freopen("8Hout.txt", "w", stdout);
while(scanf("%d%d", &n, &tot) != EOF)
{
REP_D(i, 1, n)
{
scanf("%d", &val[i]);
}
REP_D(i, 1, n)
{
scanf("%d", &num[i]);
}
solve(tot);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: