清北学堂模拟赛d2t1 一道图论神题(god)

题目描述

LYK有一张无向图G={V,E},这张无向图有n个点m条边组成。并且这是一张带权图,只有点权。

LYK想把这个图删干净,它的方法是这样的。每次选择一个点,将它删掉,但删这个点是需要代价的。假设与这个点相连的还没被删掉的点是u1,u2,…,uk。LYK将会增加a[u1],a[u2],…,a[uk]的疲劳值。

它想将所有点都删掉,并且删完后自己的疲劳值之和最小。你能帮帮它吗?

输入格式(god.in)

    第一行两个数n,m表示一张n个点m条边的图。

    第二行n个数ai表示点权。

    接下来m行每行三个数u,v,表示有一条连接u,v的边。数据保证任意两个点之间最多一条边相连,并且不存在自环。

输出格式(god.out)

你需要输出这个最小疲劳值是多少。

输入样例

4 3

10 20 30 40

1 4

1 2

2 3

输出样例

40

样例解释

一个合理的方法是先删4号点,此时有10点疲劳值。接下来删3号点,获得20点疲劳值,再删2号点,获得10点疲劳值,最后删1号点,没有疲劳值。总计40点疲劳值。

对于30%的数据n<=10。

对于60%的数据n,m<=1000。

对于100%的数据1<=n,m,ai<=100000

分析:样例给的太明显,每次先删权值最大的点,其实也很好证明,把删点转化成删边,定义一条边的边权为一对点后删的点的点权,最后每条边都是要被删掉的,先删掉点权最大的点就能尽可能地让其它点权比较大的点不被计入贡献,在统计答案的时候不需要一个点一个点地去扩展,枚举每一条边,边上两个点的权值的最小值就是这条边的贡献.

很多时候点权都可以转化为边权来思考,就能应用上许多模型.

#include <bits/stdc++.h>

using namespace std;

int n,m,a[100010];
long long ans;

int main()
{
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i++)
        scanf("%d",&a[i]);
    for (int i = 1; i <= m; i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        ans += min(a[u],a[v]);
    }
    printf("%lld
",ans);

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/7622738.html