1121: A Easy Problem
Total Submissions:48 Accepted:15
Description
小薛想吃山楂球,于是他买了n个山楂球,他想要一个一个地把这些山楂球吃掉。
遗憾的是,其中的一些山楂球黏在了一起。
小薛作为一名强迫症患者,一次吃两个山楂球在他看来是不可接受的。于是他要一个一个地把这些山楂球分开,然后丢进嘴中吃掉。
每个山楂球都有一个粘度,把一个山楂球拽出来,放到嘴里吃掉,需要付出的力气是所有与这个山楂球相连的,并且还没被吃掉的的山楂球的粘度值之和。
特别地,如果一个山楂球没有与其他任何山楂球连在一起,则吃掉它不需要花费力气。
现在,小薛已知n个山楂球的粘度值,和有哪些山楂球两两相连。
现在小薛想知道,要一个一个地把所有山楂球吃掉,最少需要付出的力气和是多少。
Input
输入的第一行包括一个整数n(1≤n≤100000),表示山楂球的数量,这些山楂球分别被标号为1 ~ n。
第二行包含n个整数,第i个整数Ai(0≤Ai≤200000)表示标号为i的山楂球的粘度值。
输入的第三行包含一个整数m(1≤m≤200000)
接下来的m行,每行包含两个不同的整数Xi和Yi,表示标号为Xi和Yi的山楂球黏在一起。
如果两个山楂球黏在一起,则这两个山楂球黏在一起的信息只会在输入文件中体现一次。
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;
}