PAT顶级(MST+优先队列——可HACK)——1024 Currency Exchange Centers (35分)

1024 Currency Exchange Centers (35分)


解题思路:

直接说吧,现在网上的版本应该是没有一个是真正对的,都无法处理以下情况:
在这里插入图片描述

很明显答案应该是只需要一个center即可,但是由于现存版本在所有center都未出现时选center的随机性,一开始会选到ACC的情况,直接导致答案错误:

输入:
3 3
0 1 ABC 1
0 2 ACC 1
1 2 ACC 1
输出:
2 2
0 1 ABC 1
0 2 ACC 1
期望:
1 2
1 2 ACC 1
0 2 ABC 1

但是将错就错,给出能AC思路:
很明显这题是MST,加了一个条件是要求中心个数最少,那么我们按照贪心思想,使用优先队列,每次优先按照fee作为第一关键字(参考克鲁斯卡尔最小生成树),该边的中心是否出现过作为第二关键字排序,即可得到“最优解”。
(一开始想过这个思路,被自己秒否决了,然后各种尝试都答案错了,最后也没能得到正解,很烦躁,浪费

代码:

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define G 6.67430*1e-11
#define  rd read()
#define pi 3.1415926535
#define pdd pair<double,double>
using namespace std;
const ll mod = 1e9 + 7;
const int MAXN = 30000005;
const int MAX2 = 300005;
inline ll read() {
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch>'9') {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
ll fpow(ll a, ll b)
{
    ll ans = 1;
    while (b)
    {
        if (b & 1)ans = ans * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return ans;
}
int fa[100005];
int find(int r) { return fa[r] == r ? r : fa[r] = find(fa[r]); }
void join(int x, int y)
{
    int fx = find(x), fy = find(y);
    fa[fx] = fy;
}
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
map<string, int> nameflag;
struct ss
{
    int s, e, fee;
    string name;
    bool operator < (const ss& b)const
    {
        return this->fee > b.fee || (this->fee == b.fee && nameflag[this->name] < nameflag[b.name]);
    }
}edge[10005];
vector<ss> ans;//存放MST的边
int sum = 0;//统计和
int namecount = 0;
priority_queue<ss> p;//<<权值*-1,编号>>
bool cmp(ss a, ss b) { return a.fee < b.fee; }
bool cmp_print(ss a, ss b) { return a.name < b.name || (a.name == b.name && a.fee < b.fee); }
signed main()
{
    int n = rd, m = rd;
    for (int i = 0; i < n; i++)fa[i] = i;
    for (int i = 0; i < m; i++)
    {
        edge[i].s = rd;
        edge[i].e = rd;
        cin >> edge[i].name;
        edge[i].fee = rd;
        p.push(edge[i]);
    }
    while (p.size())
    {
        auto now = p.top();
        if (find(now.s) != find(now.e))
        {
            if(!nameflag[now.name])namecount++;
            nameflag[now.name] = 1;//更新已存在的中心
            
            join(now.s, now.e);
            ans.push_back(now);
            sum += now.fee;
        }
        p.pop();
    }
    cout << namecount << ' ' << sum << endl;
    sort(ans.begin(), ans.end(), cmp_print);
    for (auto p : ans)
    {
        printf("%d %d %s %d\n", p.s, p.e, p.name.c_str(), p.fee);
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值