题意:给一个n个点,m条边的图,每个点有一个权值w,每删去一个点所消耗的能量为与该点相邻的点的权值之和。问消耗的最小能量是多少?
Examples
Input
4 3
10 20 30 40
1 4
1 2
2 3
Output
40
解析:很基础的一道图论题目,然而我并没有AC出来(QAQ)我的思路是这样的:我们首先将点的权值按贪心思想从大到小排序。这样在删除时大权值的点直接***掉了,不会被加进ans中。之后就是vector构图,用bfs进行图的遍历得到结果。不过提交上去代码是错的。。。
附上错误代码一份:
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 10000;
vector<int>vec[maxn];
struct Node {
int w;//权值
int num;//下标
}a[maxn];
int n, m;
bool vis[maxn];
int x, y;
int val[maxn];
bool cmp(Node p, Node q)
{
return p.w>q.w;
}
int bfs(int u, int cnt)
{
ll ans = 0;
queue<int>Q;//Q里面放点的下标
Q.push(u);
vis[u] = 1;
while (!Q.empty())
{
int v = Q.front();
vis[v] = 1;//将待删除的点做上标记
Q.pop();
for (int i = 0; i<vec[v].size(); i++) {
int t = vec[v][i];//相邻点的下标
if (!vis[t]) {
ans += val[t];
cnt++; //将次大权值的点放进队列
Q.push(a[cnt].num);
}
}
}
return ans;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &val[i]);
a[i].w = val[i];//输入点的权值
a[i].num = i;//输入点的下标
}
for (int i = 1; i <= m; i++) {
scanf("%d%d", &x, &y);
vec[x].push_back(y);//将下标放进vector里
vec[y].push_back(x);
}
sort(a + 1, a + 1 + n, cmp);//对权值进行排序
memset(vis, 0, sizeof(vis));
int u = a[1].num;
int ans = bfs(u, 1);
printf("%d\n", ans);
return 0;
}
最后被逼的没办法了,只好看大佬的代码,然后惊奇的发现这居然是一道数学思维题!!!跪了!
AC代码如下:
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 10000;
int a[maxn];
int n,m;
int x, y;
int main()
{
ios::sync_with_stdio(false);
cin >> n>>m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int ans = 0;
for (int i = 1; i <= m; i++) {
cin >> x >> y;
ans += min(a[x], a[y]);
}
cout<<ans<<endl;
return 0;
}