Lonlife-ACM 1000 - Spoon Devil's 3-D Matrix(最小生成樹)——“玲瓏杯”acm比賽-試運行賽

此文章可以使用目錄功能喲↑(點擊上方[+])

 Lonlife-ACM 1000 - Spoon Devil's 3-D Matrix

Accept: 0    Submit: 0
Time Limit: 1s    Memory Limit : 32MByte

 Problem Description

Spoon Devil build a 3-D matrix, and he(or she) wants to know if he builds some bases what's the shortest distance to connect all of them.

 Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains one integer n(0<n<50), indicating the number of all points. Then the next n lines, each lines contains three numbers xi,yi,zi indicating the position of i-th point.

 Output

For each test case, output a line, which should accurately rounded to two decimals.

 Sample Input

2
2
1 1 0
2 2 0
3
1 2 3
0 0 0
1 1 1

 Sample Output

1.41
3.97

 Hint

 Problem Idea

解題思路:

【題意】
在三維座標中有n個點

問連接這n個點的最短距離爲多少

【類型】
最小生成樹
【分析】

顯然這是一道最小生成樹的題目,如果你知道最小生成樹的話

對於最小生成樹的題目,存在兩種常用解法:prim和kruskal

這兩種算法分別是這樣描述的

prim:任選一個結點放入點集S中,一般選取結點1,即S={1},每次挑選與點集S直接相鄰的邊權最小的且不屬於點集S的結點加入點集S中,直到所有的點都加入點集S內。

舉例:


上圖爲原始的加權連通圖,每條邊一側的數字代表其權值


任選一點作爲起始點(例如結點D),頂點A、B、E和F通過單條邊與D相連,A是距離D最近的頂點,因此將A加入到點集S中,此時最短距離爲5


下一個頂點爲距離D或A最近的頂點。B距D爲9,距A爲7,E爲15,F爲6。因此,F距D或A最近,因此將頂點F加入到點集S中,此時最短距離爲5+6=11


算法繼續重複上面的步驟。距離A爲7的頂點B加入到點集S中,此時最短距離爲11+7=18


在當前情況下,可以在C、E與G間進行選擇。C距B爲8,E距B爲7,G距F爲11。點E最近,因此將頂點E加入點集S中,此時最短距離爲18+7=25


這裏,可供選擇的頂點只有C和G。C距E爲5,G距E爲9,故選取C加入點集S中,此時最短距離爲25+5=30


頂點G是唯一剩下的頂點,它距F爲11,距E爲9,E最近,故將最後的點G加入點集S中,此時最短距離爲30+9=39


現在,所有頂點均已被選取,圖中紅色部分即爲連通圖的最小生成樹。在此例中,最小生成樹的權值之和爲39。

kruskal:每次選取未在邊集E中的最短邊加入邊集E中,若選取的邊使得邊集內的圖存在迴路,則丟棄該邊,直到每個點都在邊集內

舉例:


將邊從小到大排序之後,我們率先選擇了邊AD,此時最短距離爲5


第二步,在剩下的邊中尋找。我們找到了CE。這裏邊的權重也是5,此時最短距離爲5+5=10


依次類推我們找到了6,7,7。完成之後,圖變成了這個樣子,此時最短距離爲5+5+6+7+7=30


這一步就是關鍵了。下面選擇那條邊呢? BC或者EF嗎?都不是,儘管現在長度爲8的邊是最小的未選擇的邊。但是他們已經連通了(對於BC可以通過CE,EB來連接,類似的EF可以通過EB,BA,AD,DF來接連)。所以我們不需要選擇他們。類似的BD也已經連通了。
最後就剩下EG和FG了。當然我們選擇了EG。最後成功的圖就是上圖,最短距離爲5+5+6+7+7+9=39

兩種方法均已經介紹完畢,prim配合着鄰接表或鄰接矩陣,會有兩種不同的時間複雜度做法

博主會給出三種做法的AC代碼,讀者可自行比較。

【時間複雜度&&優化】
kruskal:O(ElogE) prim+鄰接矩陣:O(V*V) prim+鄰接表:O(ElogV)

題目鏈接→Lonlife-ACM 1000 - Spoon Devil's 3-D Matrix

 Source Code

/*Sherlock and Watson and Adler*/
//Prim + 鄰接表
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 55;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
struct node
{
    double x,y,z;
}s[N];
struct edge
{
    int v,to;
    double d;
    bool operator < (const edge &a) const
    {
       return d>a.d;//最小值優先
    }
}e[N*N];
int h[N],p;
bool v[N];
void add_edge(int u,int v,double d)
{
    e[p].v=v;
    e[p].d=d;
    e[p].to=h[u];
    h[u]=p++;
    e[p].v=u;
    e[p].d=d;
    e[p].to=h[v];
    h[v]=p++;
}
double distant(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
int main()
{
    int t,n,i,j,k;
    double ans;
    edge u;
    priority_queue<edge> q;
    scanf("%d",&t);
    while(t--)
    {
        p=0;ans=0;
        while(!q.empty())
            q.pop();
        memset(h,-1,sizeof(h));
        memset(v,false,sizeof(v));
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%lf%lf%lf",&s[i].x,&s[i].y,&s[i].z);
        for(i=1;i<=n;i++)
            for(j=i+1;j<=n;j++)
                add_edge(i,j,distant(s[i],s[j]));
        v[1]=true;k=1;
        for(i=h[1];i+1;i=e[i].to)
            if(!v[e[i].v])
                q.push(e[i]);
        while(k!=n)
        {
            u=q.top();
            q.pop();
            if(v[u.v])
                continue;
            v[u.v]=true;
            k++;
            ans+=u.d;
            for(i=h[u.v];i+1;i=e[i].to)
                if(!v[e[i].v])
                    q.push(e[i]);
        }
        printf("%.2f\n",ans);
    }
    return 0;
}

/*Sherlock and Watson and Adler*/
//Prim + 鄰接矩陣
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 55;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
struct node
{
    double x,y,z;
}s[N];
struct edge
{
    int v;
    double d;
    edge(){}
    edge(int _v,double _d):v(_v),d(_d){}
    bool operator < (const edge &a) const
    {
       return d>a.d;//最小值優先
    }
};
double g[N][N];
bool v[N];
double distant(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
int main()
{
    int t,n,i,j,k;
    double ans;
    edge u;
    priority_queue<edge> q;
    scanf("%d",&t);
    while(t--)
    {
        ans=0;
        while(!q.empty())
            q.pop();
        memset(v,false,sizeof(v));
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%lf%lf%lf",&s[i].x,&s[i].y,&s[i].z);
        for(i=1;i<=n;i++)
            for(j=i+1;j<=n;j++)
                g[i][j]=g[j][i]=distant(s[i],s[j]);
        v[1]=true;k=1;
        for(i=1;i<=n;i++)
            if(!v[i])
                q.push(edge(i,g[1][i]));
        while(k!=n)
        {
            u=q.top();
            q.pop();
            if(v[u.v])
                continue;
            v[u.v]=true;
            k++;
            ans+=u.d;
            for(i=1;i<=n;i++)
                if(!v[i])
                    q.push(edge(i,g[u.v][i]));
        }
        printf("%.2f\n",ans);
    }
    return 0;
}

/*Sherlock and Watson and Adler*/
//Kruskal
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 55;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
struct node
{
    double x,y,z;
}s[N];
struct edge
{
    int u,v;
    double d;
}e[N*N/2];
bool cmp(edge x,edge y)
{
    return x.d<y.d;
}
int c[N];
int fun(int x)
{
    if(c[x]!=x)
        c[x]=fun(c[x]);
    return c[x];
}
double distant(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
int main()
{
    int t,n,i,j,p;
    double ans;
    scanf("%d",&t);
    while(t--)
    {
        ans=0;p=0;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf",&s[i].x,&s[i].y,&s[i].z);
            c[i]=i;
        }
        for(i=1;i<=n;i++)
            for(j=i+1;j<=n;j++)
            {
                e[p].u=i;e[p].v=j;
                e[p++].d=distant(s[i],s[j]);
            }
        sort(e,e+p,cmp);
        for(i=0;i<p;i++)
        {
            if(fun(e[i].u)==fun(e[i].v))
                continue;
            c[fun(e[i].u)]=fun(e[i].v);
            ans+=e[i].d;
        }
        printf("%.2f\n",ans);
    }
    return 0;
}
菜鳥成長記
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章