T1 一道数论神题

题目

【题目描述】

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

【数据规模】

对于30%的数据n≤10。

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

对于 100%的数据1≤n,m,ai≤100000。

解析

久违的送分题

贪心思想,将每个点对与其连接的点的贡献从大到小排序,依次删除即可。

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
inline int read()
{
    int num=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9')
    {
        num=(num<<1)+(num<<3)+ch-'0';
        ch=getchar();
    }
    return num;
}
const int N=100100;
struct rec{
    int w,num;
}a[N];
int n,m,b[N];
long long ans;
bool v[N];
vector<int> edge[N];
bool cmp(rec x,rec y)
{
    return x.w>y.w;
}
int main()
{
    //freopen("god.in","r",stdin);
    //freopen("god.out","w",stdout);
    memset(v,false,sizeof(v));
    n=read(),m=read();
    for(int i=1;i<=n;i++) a[i].w=read(),a[i].num=i,b[i]=a[i].w;
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        edge[x].push_back(y),edge[y].push_back(x);
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        int x=a[i].num;
        v[x]=true;
        for(int j=0;j<edge[x].size();j++)
            if(!v[edge[x][j]]) ans+=b[edge[x][j]];
    }
    cout<<ans;
    return 0;
}
View Code

相关文章: