掌握魔法の东东 I

题目:掌握魔法の东东 I
题意:东东在老家农村无聊,想种田。农田有 n 块,编号从 1~n。种田要灌氵

众所周知东东是一个魔法师,他可以消耗一定的 MP 在一块田上施展魔法,使得黄河之水天上来。他也可以消耗一定的 MP 在两块田的渠上建立传送门,使得这块田引用那块有水的田的水。 (1<=n<=3e2)

黄河之水天上来的消耗是 Wi,i 是农田编号 (1<=Wi<=1e5)

建立传送门的消耗是 Pij,i、j 是农田编号 (1<= Pij <=1e5, Pij = Pji, Pii =0)

东东为所有的田灌氵的最小消耗

输入:
第1行:一个数n

第2行到第n+1行:数wi

第n+2行到第2n+1行:矩阵即pij矩阵

输出:
东东最小消耗的MP值

样例:
Input
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0

Output
9

解题思路:把那个源头堪称一个超级源点,把田看成点;然后把超级源点和所有的点相连接,长度为那个wi;其他点之间的距离为消耗的Pij;然后最小生成树就出来了;

代码:

#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
    int u,v,w;
}edge[200005];
int parent[5005]={0},n,m;
int find(int x)
{
    return (x==parent[x])?x:find(parent[x]);
}
bool cmp(node a,node b)
{
    return a.w<b.w;
}
int main()
{
    cin>>n;
    int k=0;
    for(int i=2;i<=n+1;i++)//超级源点
    {
        int x;cin>>x;
        edge[++k].u=1;
        edge[k].v=i;
        edge[k].w=x;
    }
    for(int i=2;i<=n+1;i++)//其他的点
    {
        int x;
        for(int j=2;j<=n+1;j++)
        {
            cin>>x;
            if(j>i)
            {
                edge[++k].u=i;
                edge[k].v=j;
                edge[k].w=x;
            }
        }
    }
    for(int i=1;i<=2*n;i++)//并查集
    {
        parent[i]=i;
    }
    sort(edge+1,edge+k+1,cmp);排序
    long long sum=0;
    for(int i=1;i<=k;i++)
    {
        int eu=find(edge[i].u);
        int ev=find(edge[i].v);
        if(find(eu)==find(ev))//在同一个并查集,白给
        {
            continue;
        }
        sum+=edge[i].w;//不然就加入并查集
        parent[ev]=eu;
    }
    cout<<sum<<endl;//输出
}
发布了34 篇原创文章 · 获赞 0 · 访问量 871

猜你喜欢

转载自blog.csdn.net/qq_43653717/article/details/105151242
今日推荐