DLUT OJ 1121 A Easy Problem(贪心,倒序)

1121: A Easy Problem

Time Limit:5000/3000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:48   Accepted:15
[ Submit][ Status][ Discuss]

Description

小薛想吃山楂球,于是他买了nn个山楂球,他想要一个一个地把这些山楂球吃掉。

遗憾的是,其中的一些山楂球黏在了一起。

小薛作为一名强迫症患者,一次吃两个山楂球在他看来是不可接受的。于是他要一个一个地把这些山楂球分开,然后丢进嘴中吃掉。

每个山楂球都有一个粘度,把一个山楂球拽出来,放到嘴里吃掉,需要付出的力气是所有与这个山楂球相连的,并且还没被吃掉的的山楂球的粘度值之和。

特别地,如果一个山楂球没有与其他任何山楂球连在一起,则吃掉它不需要花费力气。

现在,小薛已知n个山楂球的粘度值,和有哪些山楂球两两相连。

现在小薛想知道,要一个一个地把所有山楂球吃掉,最少需要付出的力气和是多少。

Input

输入的第一行包括一个整数n(1n100000)n(1≤n≤100000),表示山楂球的数量,这些山楂球分别被标号为11 ~ nn

第二行包含nn个整数,第ii个整数Ai(0Ai200000)Ai(0≤Ai≤200000)表示标号为i的山楂球的粘度值。

输入的第三行包含一个整数m(1m200000)m(1≤m≤200000)

接下来的mm行,每行包含两个不同的整数XiXiYiYi,表示标号为XiXiYiYi的山楂球黏在一起。

如果两个山楂球黏在一起,则这两个山楂球黏在一起的信息只会在输入文件中体现一次。

Output

 输出包含一个整数,表示需要付出的最小力气。

Sample Input

3
1 2 3
3
1 2
2 3
1 3

Sample Output

4

HINT

 本题数据文件较大,使用cin/cout等较慢的输入输出方式可能会超出运行时间限制



题目链接:1121 A Easy Problem


题解:很容易想到,每次从粘着的一堆糖果中取出粘度最大的是最优的取法。但是问题是取完之后要维护去掉的这个糖果对于整个图的影响,这样会很复杂而且强行解决只会TLE。第一眼看到这个题我想到的是并查集,但是发现维护的困难,所以既然正着来这么困难,那就反其道而行之,我们一个一个往上加就好了,每次加的后,优先选择粘度小的糖果。

做法如下:把连接中,粘度的小的放在连接的前面,然后以每一个连接之中的左端点粘度进行排序,扫描所有的连接,每次都加上左端点的粘度,就是答案。


注意点:

1. 倒序思考的思想很重要。

2. 注意排序和交换的时候都是以粘度为基准,而不是直接的节点标号

3. 答案要开long long


代码:

#include<iostream>
#include<fstream>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdio.h>
#include<utility>
#include<algorithm>
#include<map>
#include<stack>
#include<set>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;//开最大数据的量的二倍
const int mod = 1e9+7;
const int INF = 1<<30;
const ll llINF = 1e18+999;

int arr[maxn], n, m, x, y;
struct edge
{
    int a, b;
    friend bool operator<(const edge& n1, const edge& n2)
    {
        return arr[n1.a] < arr[n2.a];
    }
};
edge in[2*maxn];
int main( )
{
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    while(~scanf("%d", &n))
    {
        ll ans = 0;
        for(int i=1; i<=n; i++)
            scanf("%d", &arr[i]);
        scanf("%d", &m);
        for(int i=0; i<m; i++)
        {
            scanf("%d%d", &x, &y);
            if(arr[x] > arr[y])
                in[i].a = y, in[i].b = x;
            else
                in[i].a = x, in[i].b = y;
        }
        sort(in, in+m);
        for(int i=0; i<m; i++)
            ans += arr[in[i].a];
        cout<<ans<<endl;
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值