CF EDU 104 E - Cheap Dinner

E - Cheap Dinner

枚举

枚举第 2 种食物,求出每个第 2 种与第 1 种食物搭配的和的最小值,把这个最小值赋给第 2 种食物

枚举第 3 种食物,求出每个第 3 种与第 2 种食物搭配的和的最小值,把这个最小值赋给第 3 种食物

枚举第 4 种食物,求出每个第 4 种与第 3 种食物搭配的和的最小值,把这个最小值赋给第 4 种食物

答案就是最小的第 4 种食物的值

枚举的过程可先排序,比如枚举第 2 种食物的每个食物与第 1 种食物的每个食物的最小值时,如果第 1 种食物是排好序的,直接从小到大找到第一个没被 ban 掉的就可以,因为 ban 掉的搭配只有 O(m) 级别,所以枚举的次数也是 O(m) 的

注意要用结构体存下每个食物的编号,因为排序后编号就乱了,而 ban 掉的搭配是按原始编号的

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1.5e5 + 10;
const ll INF = 1e18;
int n1, n2, n3, n4;
struct Node
{
	int id;
	ll val;
	bool operator<(const Node &x) const
	{
		return val < x.val;
	}
}a1[N], a2[N], a3[N], a4[N];
void solve(Node a[], Node b[], int n, int m)
{
	int q;
	cin >> q;
	set<PII> st;
	while(q--)
	{
		int x, y;
		cin >> x >> y;
		st.insert({x, y});
	}
	sort(a + 1, a + n + 1);
	sort(b + 1, b + m + 1);
	for (int i = 1; i <= m; i++)
	{
		bool flag = false;
		for (int j = 1; j <= n; j++)
		{
			if (!st.count({a[j].id, b[i].id}))
			{
				flag = true;
				b[i].val += a[j].val;
				break;
			}
		}
		if (!flag)
			b[i].val = INF;
	}

}
int main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n1 >> n2 >> n3 >> n4;
	for (int i = 1; i <= n1; i++)
		cin >> a1[i].val, a1[i].id = i;
	for (int i = 1; i <= n2; i++)
		cin >> a2[i].val, a2[i].id = i;
	for (int i = 1; i <= n3; i++)
		cin >> a3[i].val, a3[i].id = i;
	for (int i = 1; i <= n4; i++)
		cin >> a4[i].val, a4[i].id = i;
		
	solve(a1, a2, n1, n2);
	solve(a2, a3, n2, n3);
	solve(a3, a4, n3, n4);
	
	ll ans = min_element(a4 + 1, a4 + n4 + 1)->val;
	if (ans < INF / 2)
		cout << ans << endl;
	else
		cout << -1 << endl;
	return 0;
}

posted @ 2022-05-23 12:32  hzy0227  阅读(8)  评论(0编辑  收藏  举报