题意
岛上有n种宝石,有的宝石可以用魔力值合成,有的宝石不可以用魔力值合成。还有k种配方,即由几种宝石合成另一种。每一种宝石都有一个售价。现在,Panda有m的魔力值,问Panda得到的宝石最多能卖出多少钱。
思路
可以通过配方用消耗魔力值低的宝石去合成消耗魔力值低或者不能够用魔力值合成但是售价高的宝石,只要能够知道每个宝石最少需要多少魔力值合成,就可以将模型转化为物品重量为最低魔力值,价值为宝石售价,容量为m的完全背包。比赛的时候开这个题开的太晚了,只剩不到一个小时,所以没想清楚关于计算每个宝石合成所需要的“最低魔力值”如何计算,曾经想过跑最短路,但是当时没想清楚怎么建图。dijkstra处理出来之后,就是非常水的完全背包了。
注意每个宝石消耗的魔力值c[i]不能够初始化为INF,因为有的宝石可能最终也无法由任何方式合成,因此RE了好几次。其实直接把一开始无法用魔力之合成的宝石c[i]定义为m+1就可以了。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
const int maxn = 210;
const int INF = 0x3f3f3f3f;
int c[maxn], w[maxn];
int dp[10010];
vector<int> g[maxn];
bool vis[maxn];
int m, n, k;
struct node {
int to, cost;
bool operator < (const node n_) const {
return cost > n_.cost;
}
};
priority_queue<node> que;
struct node2 {
int goal;
vector<pair<int, int> > vec;
}e[maxn];
void check() {
puts("------------\n");
for(int i = 1; i <= n; i++)
printf("%d %d\n", i, c[i]);
puts("\n------------");
}
int getsum(node2& nd) {
int sum = 0;
for(int i = 0; i < nd.vec.size(); i++) {
sum += nd.vec[i].second * c[nd.vec[i].first];
}
return sum;
}
void dijkstra() {
int u, newcost;
while(!que.empty()) {
node nd = que.top();
que.pop();
u = nd.to;
if(vis[u]) continue;
vis[u] = true;
for(int i = 0; i < (int)g[u].size(); i++) {
node2& nd2 = e[g[u][i]];
newcost = getsum(nd2);
if(newcost < c[nd2.goal]) {
c[nd2.goal] = newcost;
que.push((node){nd2.goal, c[nd2.goal]});
}
}
}
}
void init() {
memset(vis, 0, sizeof vis);
memset(dp, 0, sizeof dp);
}
int main()
{
int T;
int kase = 0;
scanf("%d", &T);
while(T--) {
init();
scanf("%d%d%d", &m, &n, &k);
int flag;
for(int i = 1; i <= n; i++) {
g[i].clear();
scanf("%d", &flag);
if(flag) {
scanf("%d", &c[i]);
que.push((node){i, c[i]});
}
else {
c[i] = m+1;
}
scanf("%d", &w[i]);
}
int sum_, type_, num_;
for(int i = 0; i < k; i++) {
scanf("%d%d", &e[i].goal, &sum_);
e[i].vec.clear();
for(int j = 0; j < sum_; j++) {
scanf("%d%d", &type_, &num_);
e[i].vec.push_back(make_pair(type_, num_));
g[type_].push_back(i);
}
}
dijkstra();
//check();
for(int i = 1; i <= n; i++) {
for(int v = c[i]; v <= m; v++) {
dp[v] = max(dp[v], dp[v-c[i]]+w[i]);
}
}
printf("Case #%d: %d\n", ++kase, dp[m]);
}
return 0;
}