CF76A·gift

初见安~【第一次写CF的题解QwQ】这里是传送门:Codeforces 76A

Description

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.

有一个国家有N个城市和M条道路,这些道路可能连接相同的城市,也有可能两个城市之间有多条道路。 
有一天,有一伙强盗占领了这个国家的所有的道路。他们要求国王献给他们礼物,进而根据礼物的多少而放弃占领某些边。对于每一条道路,强盗都给出了相应的要求,金子gi的数量,银子si的数量。也就是说若国王给强盗G个金子,S个银子,那么他们就会放弃占领满足gi<=G and si<=S 的道路。 
现在国王知道金子、银子的单价,他想花费钱财购买金银送给强盗,使强盗放弃一些道路,进而使N个城市能互相到达。但是国王又想花费最少。请你计算最少的花费。 

Input

The first line of the input contains two integers N and M (2 ≤ N ≤ 200, 1 ≤ 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 ≤ N, 1 ≤ 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 .

input

3 3
2 1
1 2 10 15
1 2 4 20
1 3 5 1

output

30

Sol

当时第一反应——最小生成树板子题!很好。刚写完就发现样例就过不了——根本 没那么 简单……

我们不能只考虑金银总花费的代价,而是要一起考虑。因为就像样例那样,即使你最后得到的边的金银是(4,20),你实际要支付的却是(5,20)。也就是说我们不能合起来考虑,而是要分开考虑。

我们先按金的数量从小到大排序。这样就相当于是先固定了金的数量尽量小。枚举每条边,在当前金子的数目及以下【也就是之前选中】的边中选出最小生成树,求ans的最小。但是直接选的话其实复杂度很高的,所以我们可以把选中的边再按照银的数目从小到大排序。这样求最小生成树,最先得到一棵树的时候就是在当前金子的数目下用尽量的银子可以满足条件的时候。

总体而言就是说:因为能影响到答案的有两个变量——金子数和银子数,所以我们就固定一个,枚举一个,再固定,得到答案

上代码——

#include<bits/stdc++.h>
#define maxm 50005
#define maxn 205
#define int long long
using namespace std;
int read()
{
    int x = 0, f = 1, ch = getchar();
    while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
    while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
    return x * f;
}
 
struct node
{
    int u, v, g, s;
    long long w;
}e[maxm << 1];
 
bool cmp1(node a, node b) {return (a.g == b.g? a.s < b.s : a.g < b.g);}
 
int n, m, G, S;
int fa[maxn], cnt = 0;
int get(int x) {return fa[x] == x? x : fa[x] = get(fa[x]);}
 
map<pair<int, int>, pair<int, int> > mp;
signed main()
{
//  freopen("in.txt", "r", stdin);
    n = read(), m = read(), G = read(), S = read();
    for(int i = 1; i <= m; i++)  
        e[i].u = read(), e[i].v = read(), e[i].g = read(), e[i].s = read();
     
    sort(e + 1, e + 1 + m, cmp1);
     
    register int u, v, now;
    int ans = 0x7fffffffffffffffll;
    int stc[maxm], top = 0;
    for(int i = 1; i <= m; i++)
    {
        stc[++top] = i, cnt = 0;
        for (int j = top; j >= 2; j--) 
            if (e[stc[j]].s < e[stc[j - 1]].s) swap(stc[j], stc[j - 1]);//形如单调栈的排序维护
             
        for(int j = 1; j <= n; j++) fa[j] = j;
        for(int j = 1; j <= top; j++)
        {
            int u = e[stc[j]].u, v = e[stc[j]].v;
            if(get(u) == get(v)) continue;
            fa[get(u)] = get(v), stc[++cnt] = stc[j];//省空间+时间,替换掉不会用到的边
            if(cnt == n - 1) {ans = min(ans, e[i].g * G + e[stc[j]].s * S); break;}//最小生成树
        }
        top = cnt;//省空间的操作
    }
    printf("%lld\n", ans == 0x7fffffffffffffffll? -1 : ans);
    return 0;
}

【原来之前贴错代码了……QwQ抱歉现在才改过来】

迎评:)
——End——

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值