总共有魔力值 \(M\) , \(N\) 种水晶, \(K\) 种合成公式,每种水晶还有一个基本信息:
\(0\space p_{i}\) :该种水晶不能够由魔力值直接生成,单价为 \(p_{i}\) 。
\(1\space c_{i} \space p_{i}\) :该种水晶可以消耗 \(c_{i}\) 魔力值生成,单价为 \(p_{i}\) 。
每个合成公式的形式为:
\(x_{i}\space y_{i}\space u_{1}\space v_{1}...\) :表示第 \(x_{i}\) 种水晶可以由 \(y_{i}\) 种水晶一起合成,其中第 \(u_{j}\) 种水晶需要 \(v_{j}\) 个。
求所拥有的魔力值可以制造出的最大水晶价值。
我们可以考虑去求出能够获取某种水晶所需要花费的最小魔力值,然后做一个完全背包来求出最后的答案。对于求出最小魔力值的部分,记 \(d[i]\) 为第 \(i\) 种水晶所需的最小魔力值,于是每个公式可以写成 \(d[x_{i}]=\sum_{j=1}^{y_{i}}v_{j}*d[u_{j}]\) 的形式,我们可以建立一张有向图,如果水晶 \(u\) 的最小魔力值会对水晶 \(v\) 的最小魔力值通过公式 \(id\) 产生影响,那么我们就从 \(u\) 到 \(v\) 连一条权值为 \(id\) 的边,然后我们通过 \(dijkstra\) 来对所有的边,也就是对应的公式进行类似松弛的操作就可以求得了。
#include<bits/stdc++.h> #include<unordered_map> #include<unordered_set> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PII; #define all(x) x.begin(),x.end() //#define int LL //#define lc p*2+1 //#define rc p*2+2 #define endl '\n' #define inf 0x3f3f3f3f #define INF 0x3f3f3f3f3f3f3f3f #pragma warning(disable : 4996) #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) const double eps = 1e-8; const LL MOD = 1000000007; const LL mod = 998244353; const int maxn = 210; const int maxk = 210; struct edge { int to, id; }; int T, cnt = 0; int M, N, K; int t[maxn], c[maxn], p[maxn]; int d[maxn]; priority_queue<PII, vector<PII>, greater<PII>>que; vector<edge>G[maxn]; int dp[10010]; vector<PII>eq[maxn]; void add_edge(int from, int to, int cost) { G[from].push_back({ to,cost }); } void dijkstra() { memset(d, inf, sizeof(d)); for (int i = 1; i <= N; i++) { if (t[i]) { d[i] = c[i]; que.push(PII(d[i], i)); } } while (!que.empty()) { PII p = que.top(); que.pop(); int v = p.second; if (d[v] < p.first) continue; for (int i = 0; i < G[v].size(); i++) { edge& e = G[v][i]; int sum = 0; for (int j = 0; j < eq[e.id].size(); j++) { int num = eq[e.id][j].second, ty = eq[e.id][j].first; if (d[ty] == inf) { sum = -1; break; } sum += d[ty] * num; } if (sum != -1 && sum < d[e.to]) { d[e.to] = sum; que.push(PII(d[e.to], e.to)); } } } } void solve() { dijkstra(); for (int i = 1; i <= N; i++) { for (int j = 1; j <= M; j++) { if (j >= d[i]) dp[j] = max(dp[j], dp[j - d[i]] + p[i]); } } int ans = 0; for (int i = 0; i <= M; i++) ans = max(ans, dp[i]); cout << "Case #" << cnt << ": " << ans << endl; } int main() { IOS; cin >> T; while (T--) { for (int i = 1; i <= N; i++) G[i].clear(); for (int i = 0; i <= K; i++) eq[i].clear(); for (int i = 0; i <= M; i++) dp[i] = 0; cnt++; cin >> M >> N >> K; for (int i = 1; i <= N; i++) { cin >> t[i]; if (t[i]) cin >> c[i] >> p[i]; else cin >> p[i]; } int x, y, u, v; for (int i = 1; i <= K; i++) { cin >> x >> y; for (int j = 1; j <= y; j++) { cin >> u >> v; eq[i].push_back(PII(u, v)); add_edge(u, x, i); } } solve(); } return 0; }