upc 兔 最小生成树


时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
小粉兔用集训队的奖金买下了一片地。

这片地上有 n 个房子,有些房子之间有道路,有些房子之间则是杂草。

她可以花费一定的代价拆毁一条道路,或是啃光一片草使得两个房子间可以通行(大雾)。

她喜欢生成树,所以她要让所有道路形成一棵生成树。

求最小花费。
输入
第一行一个数,n。

接下来 n 行,每行 n 个数,代表 ai,j。如果为正数,说明它们之间没有道路,需要 ai,j的花费来修建;如果为负数,说明它们之间有道路,需要 −ai,j的花费来拆毁。
输出
一行一个数,代表最小花费。
样例输入 Copy
3
0 1 -3
1 0 5
-3 5 0
样例输出 Copy
1
提示
对于 100% 的数据,5≤n≤1000,1≤|ai,j(i≠j)|≤1000,保证所有 ai,i=0且 ai,j=aj,i 。

题意就是让你在给定条件下,生成一棵树,可以在某些点之间建边,也可以删给定的边。
先不考虑建边,先考虑已经有的边,这些已经有的边,本着能不删就不删的原则 ( 这是显然的,因为删去的话可能需要重新建一条边 ) ,从大到小枚举已经有的边,能加入并查集合并的就合并,如果当前边连接的两个点已经在同一个集合当中,这个时候,因为树的结构的限制,一定需要删除这条边,而且我们是从大到小枚举的,所以删除边的代价是最小的。
至此,我们能留下的原有的边是最多的,现在需要做的就是补充完树的结构,对于可以建的边做一遍最小生成树即可。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=1010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n;
int p[N*N*2];
int g[N][N];
struct Node
{
    int a,b;
    int w;
    bool operator < (const Node &s) const
    {
        return w<s.w;
    }
}edge1[N*N*2],edge2[N*N*2];

void init(int n)
{
    for(int i=1;i<=n;i++)
        p[i]=i;
}

int find(int x)
{
    if(x!=p[x]) p[x]=find(p[x]);
    return p[x];
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    int tot=0,cos=0,cnt=0;
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            int x;
            scanf("%d",&x);
            if(i<=j) continue;
            if(x>0) edge1[++tot]={i,j,x};
            else edge2[++cnt]={i,j,-x};
        }

    init(max(tot,cnt));
    sort(edge2+1,edge2+1+cnt);
    for(int i=cnt;i>=1;i--)
    {
        int a=edge2[i].a,b=edge2[i].b;
        int pa=find(a),pb=find(b);
        int w=edge2[i].w;
        if(pa!=pb)
            p[pa]=pb;
        else cos+=w;
    }

    sort(edge1+1,edge1+1+tot);
    for(int i=1;i<=tot;i++)
    {
        int a=edge1[i].a,b=edge1[i].b;
        int w=edge1[i].w;
        int pa=find(a),pb=find(b);
        if(pa!=pb)
        {
            cos+=w;
            p[pa]=pb;
        }
    }



    cout<<cos<<endl;




	return 0;
}

猜你喜欢

转载自blog.csdn.net/DaNIelLAk/article/details/106246073
UPC