1. 程式人生 > 其它 >2016CCPC Final I. Mr. Panda and Crystal

2016CCPC Final I. Mr. Panda and Crystal

題目大意

總共有魔力值 \(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;
}