一道图论神题
Time Limit:1000ms Memory Limit:128MB
题目描述
LYK有一张无向图G={V,E},这张无向图有n个点m条边组成。并且这是一张带权图,只有点权。
LYK想把这个图删干净,它的方法是这样的。每次选择一个点,将它删掉,但删这个点是需要代价的。假设与这个点相连的还没被删掉的点是u1,u2,…,uk。LYK将会增加a[u1],a[u2],…,a[uk]的疲劳值。
它想将所有点都删掉,并且删完后自己的疲劳值之和最小。你能帮帮它吗?
输入格式
第一行两个数n,m表示一张n个点m条边的图。
第二行n个数ai表示点权。
接下来m行每行三个数u,v,表示有一条连接u,v的边。数据保证任意两个点之间最多一条边相连,并且不存在自环。
输出格式
你需要输出这个最小疲劳值是多少。
输入样例
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
题解
把删点转化成删边,定义一条边的边权为一对点后删的点的点权,最后每条边都是要被删掉的。
对于每条边,肯定优先删除点权大的点。
正确性证明:将无向图中的边按点权大的点向点权小的点连有向边,最后一定是一张DAG图。
代码
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #define LL long long using namespace std; const int N=100005; int n,m; int a[100005]; LL ans; int main(){ scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%d",&a[i]); int u,v; while(m--){ scanf("%d%d",&u,&v); ans+=min(a[u],a[v]); } printf("%lld ",ans); return 0; }