Connect the Campus (Uva 10397 Prim || Kruskal + 并查集)

题意:给出n个点的坐标,要把n个点连通,使得总距离最小,可是有m对点已经连接,输入m,和m组a和b,表示a和b两点已经连接。

思路:两种做法。(1)用prim算法时,输入a,b。令mp[a][b]=0。然后进行一遍prim(2)Kruskal算法+并查集

代码:

//prim写法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b)  for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define DBG         pf("Hi\n")
typedef long long ll;
using namespace std;

#define INF 0x3f3f3f3f
#define mod 1000000009
const int maxn = 1005;
const int MAXN = 2005;
const int MAXM = 200010;
const int N = 1005;

struct Node
{
    double x,y;
}node[maxn];

int n,m;
double mp[maxn][maxn];
double dist[maxn];
bool vis[maxn];

double Dis(Node n1,Node n2)
{
    return sqrt((n1.x-n2.x)*(n1.x-n2.x)+(n1.y-n2.y)*(n1.y-n2.y));
}

double prim()
{
    int i,j,now;
    double mi;
    mem(vis,false);
    mem(dist,INF);
    for (i=1;i<=n;i++)
        dist[i]=mp[1][i];
    dist[1]=0;
    vis[1]=true;
    for (i=1;i<=n;i++)
    {
        now=-1;
        mi=INF;
        for (j=1;j<=n;j++)
        {
            if (!vis[j]&&mi>dist[j])
            {
                now=j;
                mi=dist[j];
            }
        }
        if (now==-1) break;
        vis[now]=true;
        for (j=1;j<=n;j++)
        {
            if (!vis[j]&&dist[j]>mp[now][j])
                dist[j]=mp[now][j];
        }
    }
    double ans=0;
    for (i=1;i<=n;i++)
        ans+=dist[i];
    return ans;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("C:/Users/lyf/Desktop/IN.txt","r",stdin);
#endif
    int i,j,u,v;
    while (~sf(n))
    {
        for (i=1;i<=n;i++)
            scanf("%lf%lf",&node[i].x,&node[i].y);
        for (i=1;i<=n;i++)
        {
            for (j=1;j<=n;j++)
                if (i==j) mp[i][j]=0;
                else mp[i][j]=Dis(node[i],node[j]);
        }
        sf(m);
        for (i=0;i<m;i++)   //在同一个联通块的距离直接赋为0
        {
            sff(u,v);
            mp[u][v]=mp[v][u]=0;
        }
        printf("%.2f\n",prim());
    }
    return 0;
}

//Kruskal+并查集写法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b)  for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define DBG         pf("Hi\n")
typedef long long ll;
using namespace std;

#define INF 0x3f3f3f3f
#define mod 1000000009
const int maxn = 1005;
const int MAXN = 1000000;
const int MAXM = 200010;
const int N = 1005;

struct Node
{
    double x,y;
}node[maxn];

struct Edge
{
    int u,v;
    double len;
}edge[MAXN];

int n,m,cnt;
int father[maxn];

int cmp(Edge e1,Edge e2)
{
    return e1.len<e2.len;
}

void init()
{
    cnt=0;
    for (int i=0;i<=n;i++)
        father[i]=i;
}

double Dis(Node n1,Node n2)
{
    return sqrt((n1.x-n2.x)*(n1.x-n2.x)+(n1.y-n2.y)*(n1.y-n2.y));
}

int find_father(int x)
{
    if (x!=father[x])
        father[x]=find_father(father[x]);
    return father[x];
}

double Kruskal()
{
    int i,j;
    double ans=0;
    sort(edge,edge+cnt,cmp);
    for (i=0;i<cnt;i++)
    {
        int fu=find_father(edge[i].u);
        int fv=find_father(edge[i].v);
        if (fu!=fv)
        {
            ans+=edge[i].len;
            father[fu]=fv;
        }
    }
    return ans;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("C:/Users/lyf/Desktop/IN.txt","r",stdin);
#endif
    int i,j,u,v;
    while (~sf(n))
    {
        init();
        for (i=1;i<=n;i++)
            scanf("%lf%lf",&node[i].x,&node[i].y);
        for (i=1;i<n;i++)
        {
            for (j=i+1;j<=n;j++)
            {
                if (i==j) continue;
                else
                {
                    double x=Dis(node[i],node[j]);
                    edge[cnt].u=i;
                    edge[cnt].v=j;
                    edge[cnt++].len=x;
                }
            }
        }
        sf(m);
        for (i=1;i<=m;i++)
        {
            sff(u,v);
            int fu=find_father(u);
            int fv=find_father(v);
            if (fu!=fv)
                father[fu]=fv;
        }
        printf("%.2f\n",Kruskal());
    }
    return 0;
}

时间: 2024-10-13 07:04:56

Connect the Campus (Uva 10397 Prim || Kruskal + 并查集)的相关文章

ACM:最小生成树,kruskal &amp;&amp; prim,并查集

题目: 输入顶点数目,边的数目,输入每条边的两个顶点编号还有每条边的权值,求最小生成树,输出最小生成树的权值.. 注意:prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图. kruskal----归并边:prim----归并点 方法一:kruskal,克鲁斯卡尔,并查集实现. #include <iostream> #include <algorithm> using name

SDUT 2933-人活着系列之Streetlights(最小生成树Kruskal+并查集实现)

人活着系列之Streetlights Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 人活着如果是为了家庭,亲情----可以说是在这个世界上最温暖人心的,也是最让人放不下的,也是我在思索这个问题最说服自己接受的答案.对,也许活着是一种责任,为了繁殖下一代,为了孝敬父母,男人要养家糊口,女人要生儿育女,就这样循环的过下去,但最终呢?还是劳苦愁烦,转眼成空呀! 为了响应政府节约能源的政策,某市要对路灯进行改革,已知该市有n个城镇,

UVA 10158 War(并查集)

War A war is being lead between two countries, A and B. As a loyal citizen of C, you decide to help your country's espionage by attending the peace-talks taking place these days (incognito, of course). There are n people at the talks (not including y

最小生成树(kruskal+并查集)

最小生成树 最小生成树即用最少的边权将所有给定的点连在同一联通分量中,常用kruskal和prim算法 kruskal算法(适合稀疏图) 最小生成树的kruskal算法,稍带并查集的应用 int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); //不要漏了fa[x]=... } int kruskal() { int ans=0; for(int i=0;i<N;i++) fa[i]=i;//初始化并查集 sort(edge,edge+e);

codevs 1078最小生成树 Kruskal+并查集

题目描述 Description 农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场.当然,他需要你的帮助. 约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场.为了使花费最少,他想铺设最短的光纤去连接所有的农场. 你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案. 每两个农场间的距离不会超过100000 输入描述 Input Description 第一行: 农场的个数,N(3<=N<=100).

uva 10608 Friends(并查集)

uva 10608 Friends 题目大意:给出两两之间的关系,求出最大的关系网. 解题思路:并查集裸体. #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <cstdlib> using namespace std; const int N = 30005; typedef long long ll; int n, m; in

uva 12232 - Exclusive-OR(加权并查集)

题目链接:uva 12232 - Exclusive-OR 题目大意:有n个数,一开始并不知道具体的值,现在进行Q次操作. I u k:au的值为k I u v k:au?av=k Q k q1q2-qk:求q1?q2-?qk 对于Q操作不能确定的话输出"I don't know." 对于I操作矛盾的话则输出是第几条I操作出现矛盾的,并且停止后面所有的操作. 解题思路:加权并查集,f[x]表示x节点父亲节点,d[x]表示x节点与其父节点的亦或值,对于确定的节点值,可以将父亲节点设为0,

UVA 11987 - Almost Union-Find(并查集)

UVA 11987 - Almost Union-Find 题目链接 题意:给定一些集合,操作1是合并集合,操作2是把集合中一个元素移动到另一个集合,操作3输出集合的个数和总和 思路:并查集,关键在于操作2,对于并查集,要去除掉一个结点,如果该结点不是根那就好办了,那么就多开n个结点,每个结点初始父亲都是它的i + n,这样在移动的时候,就不用担心他是根结点了剩下就是普通的带权并查集了 代码: #include <cstdio> #include <cstring> const i

UVA 10608 Friends【并查集】

题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1549 题意:给定n个人m种朋友关系,求最大朋友圈的人数.裸并查集 代码: #include <stdio.h> #include <iostream> #include <string.h> #include <algorithm>