CodeForces 76A Gift (最小生成树 克鲁斯卡尔)

A. Gift
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

The kingdom of Olympia consists of N cities and M bidirectional roads. Each road connects exactly two cities and two cities can be connected with more than one road. Also it possible that some roads connect city with itself making a loop.

All roads are constantly plundered with bandits. After a while bandits became bored of wasting time in road robberies, so they suggested the king of Olympia to pay off. According to the offer, bandits want to get a gift consisted of gold and silver coins. Offer also contains a list of restrictions: for each road it is known gi — the smallest amount of gold and si — the smallest amount of silver coins that should be in the gift to stop robberies on the road. That is, if the gift contains a gold and b silver coins, then bandits will stop robberies on all the roads that gi ≤ a and si ≤ b.

Unfortunately kingdom treasury doesn't contain neither gold nor silver coins, but there are Olympian tugriks in it. The cost of one gold coin in tugriks is G, and the cost of one silver coin in tugriks is S. King really wants to send bandits such gift that for any two cities there will exist a safe path between them. Your task is to find the minimal cost in Olympian tugriks of the required gift.

Input

The first line of the input contains two integers N and M (2 ≤ N ≤ 2001 ≤ M ≤ 50 000) — the number of cities and the number of roads, respectively. The second line contains two integers G and S (1 ≤ G, S ≤ 109) — the prices of gold and silver coins in tugriks. The following M lines contain information about the offer. Each of the records in list is given as four integers xi, yi, gi, si, where xi and yi are the numbers of cities that the road connects and gisi are minimal gold and silver coins requirements for the i-th road (1 ≤ xi, yi ≤ N1 ≤ gi, si ≤ 109). Cities are numbered from 1 to N. It is possible that there are more than one road between a pair of cities. It is possible that a road connects the city with itself.

Output

The output should contain the minimal cost of the gift in Olympian tugriks. If there is no gift that satisfies the given requirements output .

Examples
input
Copy
3 3
2 1
1 2 10 15
1 2 4 20
1 3 5 1
output
Copy
30

一、原题地址

        传送门


二、大致题意

    有n个城市m条路,现在有一群强盗向城主索要赎金,他们给每一条路标定了对应的价值,至少需要gi个金块和si个银块才能保证这条路不被他们洗劫。城主没有金块,但是他有一种名为tug的货币,用G个这样的tug货币可以换一个金子,S个tug货币可以换一个银块。当交给强盗A个金块B个银块时,所有费用小于等于A个金块B个银块的路径都可以保证平安。

    询问的是连通所有城镇所需要的最小的tug货币数量。


三、思路

    首先想到的是最小生成树问题,但是这里每条路的权值有两个,所以我们可以将每一条边先按照第一种价值进行排序。然后进行m次操作,每次操作取一条当前gi值最小的边加入到待操作的边堆stc里面。这样我们就相当于在处理一个权值的最小生成树问题了。

    但是这样一来复杂度就太大了。对于最小生成树来讲,每次生成的这条边已经是一个最优的解了,也就是说在当前的第x操作时我们连通的边,在第x+1次的操作里面也一定是会被连通的,那么我们就可以在求解生成树的时候不停的更新边堆,去掉不需要重复操作的多余边就可以大大降低复杂度。

    在我们求出生成树后,问题的答案就是( 这些边里gi最大的乘以G+这些边里si最大的乘以S).


四、代码

    

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<list>
using namespace std;
const int INF = 0x3f3f3f3f;
#define LL long long int 
#define PI 3.14159265
long long  gcd(long long  a, long long  b) { return a == 0 ? b : gcd(b % a, a); }



const int N = 50005;
int n, m, G, S;
LL ans;
struct edge
{
	int from, to;
	LL wg, ws;
};
int cnt,tt;
edge e[N], stc[N];
int pre[N];
int find(int x)
{
	if (x == pre[x])
		return x;
	return pre[x] = find(pre[x]);
}
void init()
{
	for (int i = 1; i <= n; ++i)
		pre[i] = i;
}
bool cmp(edge xx, edge yy)
{
	if (xx.wg != yy.wg)return xx.wg < yy.wg;
	else return xx.ws < yy.ws;
}
void Kruskal()
{
	tt = 0;
	ans = 0x3f3f3f3f3f3f3f3fll;
	for (int i = 0; i < m; i++)
	{
		init();
		stc[tt++] = e[i];
		LL maxx = -INF;
		for (int j = tt - 1; j >= 1; j--)
		{
			if (stc[j].ws < stc[j - 1].ws)
				swap(stc[j], stc[j - 1]);
		}
		int hav = 0;
		for (int j = 0; j<tt; ++j)
		{
			int u = find(stc[j].from);
			int v = find(stc[j].to);
			if (u != v)
			{
				maxx = max(maxx, stc[j].ws);
				stc[hav++] = stc[j];
				pre[u] = v;
			}
			if (hav == n - 1) break;
		}
		if (hav == n - 1)
		{
			ans = min(ans, e[i].wg*G + maxx*S);
		}
		tt = hav;
	}
}


int main() 
{
	scanf("%d%d", &n, &m);
	scanf("%d%d", &G, &S);
	for (int i = 0; i < m; i++)
	{
		scanf("%d%d%lld%lld", &e[i].from, &e[i].to, &e[i].wg, &e[i].ws);
	}
	sort(e, e + m, cmp);
	Kruskal();
	if (ans == 0x3f3f3f3f3f3f3f3fll)
		printf("-1\n");
	else
		printf("%lld\n", ans);
	getchar();
	getchar();
} 


猜你喜欢

转载自blog.csdn.net/Amovement/article/details/80909562