CSUST 7月31日 并查集 & 最小生成树

这一次的练习基本都是一个模板,一个代码改来改去可以A几道题。这次题目也充满滑稽性,还有就是大部分都是中文题,看着舒服多了,不用去死抠某个单词的意思是什么,也不会因为担心哪句话看不懂而影响做题思路,更重要的是不会看着头晕。

练习地址:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=85388#overview   密码:acmore


Problem A          HDU 1213     How Many Tables

Description
Today is Ignatius' birthday. He invites a lot of friends. Now it's dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers. 


One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table. 


For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least. 
 
Input
The input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases. 
 
Output
For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks. 


 
Sample Input
2
5 3
1 2
2 3
4 5


5 1
2 5 
 


Sample Output
2


题目意思是说n个人,如果两个人是朋友就可以坐在一起吃饭,如果A和B是朋友,B和C也是朋友,那么A,B,C都是朋友可以同桌,问这n个人最少需要多少张桌子。

一看题目就知道是并查集,还是裸的,立马敲出来,A 了。

不多说,直接上代码。。。


<span style="font-size:18px;">/*
ZXPxx 's source code for A
Memory: 1620 KB		Time: 15 MS
Language: C++		Result: Accepted
*/


#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=1011;
int p[maxn];
int find(int x)
{
    return x==p[x]?x:p[x]=find(p[x]);
}
void Union(int a,int b)
{
    int x=find(a);
    int y=find(b);
    if(x!=y)
        p[x]=y;
}

int main()
{
    int t,n,m,a,b,x,y;
    scanf("%d",&t);
    while(t--)
    {
        memset(p,0,sizeof(p));
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
            p[i]=i;
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&a,&b);
            Union(a,b);
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            if(p[i]==i)
                ans++;
        printf("%d\n",ans);
    }
    return 0;
}
</span>


Problem B        POJ 2236Wireless Network

Description
An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computers, but an unexpected aftershock attacked, all computers in the network were all broken. The computers are repaired one by one, and the network gradually began to work again. Because of the hardware restricts, each computer can only directly communicate with the computers that are not farther than d meters from it. But every computer can be regarded as the intermediary of the communication between two other computers, that is to say computer A and computer B can communicate if computer A and computer B can communicate directly or there is a computer C that can communicate with both A and B. 


In the process of repairing the network, workers can take two kinds of operations at every moment, repairing a computer, or testing if two computers can communicate. Your job is to answer all the testing operations. 
Input
The first line contains two integers N and d (1 <= N <= 1001, 0 <= d <= 20000). Here N is the number of computers, which are numbered from 1 to N, and D is the maximum distance two computers can communicate directly. In the next N lines, each contains two integers xi, yi (0 <= xi, yi <= 10000), which is the coordinate of N computers. From the (N+1)-th line to the end of input, there are operations, which are carried out one by one. Each line contains an operation in one of following two formats: 
1. "O p" (1 <= p <= N), which means repairing computer p. 
2. "S p q" (1 <= p, q <= N), which means testing whether computer p and q can communicate. 


The input will not exceed 300000 lines. 
Output
For each Testing operation, print "SUCCESS" if the two computers can communicate, or "FAIL" if not.


Sample Input
4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4


Sample Output
FAIL
SUCCESS


题目意思是说有N台电脑全都是坏的,现在给出每台电脑的坐标和每两台电脑要联机需满足的距离要求。然后惊醒两种操作:(1)输入“O  p”,O为字符,p为整数,意思是修好第p台电脑。(2)输入“S p q”,S是字符,p,q为整数,意思是询问p,q两台电脑是否能联机。注意:联机的前提是电脑必须是好的,坏了的电脑联机有毛用啊。假设1与2可以联机,2和3可以联机,那么久表示1和3也可以联机。典型的并查集嘛\(^o^)/~!!!

好可惜(⊙o⊙)在比赛时没来得及看这道题,当时做这道题的人也很少,以为很难,就把它放在一边了,赛后一看其实也不是很难,就是多了一个距离判断函数而已,其实也顶多就是个并查集的应用。


/*
ZXPxx 's source code for B
Memory: 196 KB		Time: 1094 MS
Language: C++		Result: Accepted
*/

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn=10011;
int fa[maxn],vis[maxn],x[maxn],y[maxn];
int n,d,p,q;
char s[3];
int find(int x)
{
    return x==fa[x]?x:fa[x]=find(fa[x]);
}

int distant(int a,int b)
{
    double x0=abs(x[a]-x[b]);
    double y0=abs(y[a]-y[b]);
    if(x0*x0+y0*y0<=d*d)
        return 1;
    return 0;
}

void Union(int a,int b)
{
    int x=find(a);
    int y=find(b);
    if(x!=y)
        fa[x]=y;
}

int main()
{
    while(~scanf("%d%d",&n,&d))
    {
        for(int i=1; i<=n; i++)
        {
            fa[i]=i;
            vis[i]=0;                           //所有电脑一开始都是坏的
            scanf("%d%d",&x[i],&y[i]);
        }
        while(~scanf("%s",s))
        {
            if(s[0]=='O')
            {
                scanf("%d",&p);
                if(!vis[p])
                {
                    vis[p]=1;
                    for(int i=1; i<=n; i++)
                    {
                        if(vis[i] && i!=p && distant(i,p))  //电脑是好的,并且满足距离要求
                            Union(i,p);
                    }
                }
            }
            else if(s[0]=='S')
            {
                scanf("%d%d",&p,&q);
                int x=find(p);
                int y=find(q);
                if(x==y)
                    printf("SUCCESS\n");
                else
                    printf("FAIL\n");
            }

        }
    }
    return 0;
}


Problem CPOJ 1611The Suspects

Description
严重急性呼吸系统综合症( SARS), 一种原因不明的非典型性肺炎,从2003年3月中旬开始被认为是全球威胁。为了减少传播给别人的机会, 最好的策略是隔离可能的患者。
在Not-Spreading-Your-Sickness大学( NSYSU), 有许多学生团体。同一组的学生经常彼此相通,一个学生可以同时加入几个小组。为了防止非典的传播,NSYSU收集了所有学生团体的成员名单。他们的标准操作程序(SOP)如下:
一旦一组中有一个可能的患者, 组内的所有成员就都是可能的患者。
然而,他们发现当一个学生被确认为可能的患者后不容易识别所有可能的患者。你的工作是编写一个程序, 发现所有可能的患者。
 
Input
输入文件包含多组数据。
对于每组测试数据:
第一行为两个整数n和m, 其中n是学生的数量, m是团体的数量。0 < n <= 30000,0 <= m <= 500。
每个学生编号是一个0到n-1之间的整数,一开始只有0号学生被视为可能的患者。
紧随其后的是团体的成员列表,每组一行。
每一行有一个整数k,代表成员数量。之后,有k个整数代表这个群体的学生。一行中的所有整数由至少一个空格隔开。
n = m = 0表示输入结束,不需要处理。

Output
对于每组测试数据, 输出一行可能的患者。

Sample Input
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0

Sample Output
4
1
1


此题属于按秩合并的并查集。作为一道中文题,相信不难被理解,就不做太多解释了。个人认为这题比B稍难,可是比赛时这题出的人远远超过B题。最开始还画蛇添足的考虑了一下0不出现的情况,之后听别人说0一定会出现才改过来。其实也都差不多,直接上代码吧!


/*
ZXPxx 's source code for C
Memory: 360 KB		Time: 16 MS
Language: C++		Result: Accepted
*/

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=30000+10;

int p[maxn],vis[maxn]; //p[]储存父亲节点,vis[]储存秩即某集合中元素的个数

int find(int x)         //查找元素所在集合,并返回根节点
{
    return x==p[x]?x:p[x]=find(p[x]);
}

void Union(int a,int b)   //按秩合并a,b所在集合
{
    int x=find(a);
    int y=find(b);
    //printf("%d^^%d^^\n",x,y);
    if(x!=y)
    {
        p[x]=y;
        vis[y]+=vis[x];     //记得更新秩
    }
}

int main()
{
    int t,n,m,a,b,x,y;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0 && m==0)
            break;
        memset(vis,0,sizeof(vis));
        for(int i=0; i<=n; i++)
        {
            p[i]=i;
            vis[i]=1;           //初始化,秩为1
        }
        while(m--)
        {
            scanf("%d", &t);
            if(t >= 1) scanf("%d", &a);
            for(int j=2; j<=t; j++)
            {
                scanf("%d", &b);
                Union(b, a);
            }
        }
        printf("%d\n", vis[find(0)]);       //只需找出0元素所在集合的秩即可
    }
    return 0;
}

Problem DPOJ 1182食物链

这题是最可惜的了,去年就一直在看学姐写的题解,可是没看懂就一直放在收藏夹里没看了,这次又遇到了这题,只能干看着。学姐的题解写的好好哦\(^o^)/~,分析的很透彻。我就不献丑了,还是直接附上学姐的题解地址吧~~~

http://blog.csdn.net/freezhanacmore/article/details/8767413

我也还要去认真看看……(*^__^*) 


Problem EHDU 1232畅通工程


O__O"…这是一道大水题,做过好几次了,直接通过A题改改代码就AC了。


/*
ZXPxx 's source code for E
Memory: 1624 KB		Time: 31 MS
Language: C++		Result: Accepted
*/


#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=1011;
int p[maxn];
int find(int x)
{
    return x==p[x]?x:p[x]=find(p[x]);
}
void Union(int a,int b)
{
    int x=find(a);
    int y=find(b);
    if(x!=y)
        p[x]=y;
}

int main()
{
    int n,m,a,b,x,y;
    while(~scanf("%d",&n),n)
    {
        scanf("%d",&m);
        memset(p,0,sizeof(p));
        for(int i=1; i<=n; i++)
            p[i]=i;
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&a,&b);
            Union(a,b);
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            if(p[i]==i)
                ans++;
        printf("%d\n",ans-1);
    }
    return 0;
}

Problem FHDU 1863畅通工程 


Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。 
 
Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N 
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。 
 
Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。 
 
Sample Input
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100 
 
Sample Output
3
?


这题在E题的基础上增加了一点难度,属于最小生成树中典型的简单例题。有Kruskal和Prim两种算法。

第一种:Kruskal算法代码


/*
ZXPxx 's source code for F
Memory: 1608 KB		Time: 0 MS
Language: C++		Result: Accepted
*/

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=105;
int n,m,p[maxn];
struct node
{
    int u;
    int v;
    int w;
}f[maxn];
int find(int x)
{
    return p[x]==x ? p[x]:p[x]=find(p[x]);
}
int cmp(node a,node b)
{
    return a.w<b.w;
}
void Kruskal()
{
    int sum=1,ans=0,x,y;
    memset(p,0,sizeof(p));
    sort(f,f+n,cmp);
    for(int i=1;i<=n;i++)
        p[i]=i;
    for(int i=1;i<=n;i++)
    {
        x=find(f[i].u);
        y=find(f[i].v);
        if(x!=y)
        {
            sum++;
            ans+=f[i].w;
            p[x]=y;
        }
    }
    if(sum==m)
        printf("%d\n",ans);
    else
        printf("?\n");
}
int main()
{

    while(~scanf("%d%d",&n,&m)&&n)
    {

        for(int i=1;i<=n;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            f[i].u=a;
            f[i].v=b;
            f[i].w=c;
        }
        Kruskal();
    }
    return 0;
}

第二种:prim算法代码

/*
ZXPxx 's source code for F
Memory: 1680 KB		Time: 0 MS
Language: C++		Result: Accepted
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define max 100000000

int map[200][200];
int temp[200];
int visit[200];
int n,m;

void prim()
{
    for(int i=1;i<=m;i++)
        temp[i]=map[1][i];
    int index,min;
    int sum=0;
    memset(visit,0,sizeof(visit));
    visit[1]=1;
    for(int i=1;i<m;i++)
    {
        min=max;
        for(int j=1;j<=m;j++)
        if(!visit[j] && min>temp[j])
        {
            index=j;
            min=temp[j];
        }
        if(min==max)
        {
            printf("?\n");
            return;
        }
        sum+=min;
        visit[index]=1;
        for(int j=1;j<=m;j++)
        {
            if(!visit[j] && j != index&& map[j][index]<temp[j])
                temp[j]=map[j][index];
        }
    }
    printf("%d\n",sum);
}

int main()
{
    while(~scanf("%d",&n),n)
    {
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                if(i==j)
                    map[i][j]=0;
                else
                    map[i][j]=max;
        int x,y,z;
        for(int i=1;i<=n;i++)
        {

            scanf("%d%d%d",&x,&y,&z);
            if(map[x][y]>z)
                map[x][y]=map[y][x]=z;
        }
        prim();
    }
	return 0;
}

Problem GHDU 1233还是畅通工程

Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。 
 
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。 
当N为0时,输入结束,该用例不被处理。 
 
Output
对每个测试用例,在1行里输出最小的公路总长度。 
 
Sample Input
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5

 
Sample Output
3

Hint
Hint  Huge input, scanf is recommended.
        

这题也跟上题相似,只需稍微改改代码即可。这里只展示kruskal算法的代码。


/*
ZXPxx 's source code for G
Memory: 1696 KB		Time: 265 MS
Language: C++		Result: Accepted
*/


#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=110000;
int p[maxn],m,n,sum;
struct node
{
    int u,v,w;
} fuck[maxn];


int cmp(node x,node y)
{
    return x.w<y.w;
}

int find(int x)
{
    return x==p[x]?p[x]:p[x]=find(p[x]);
}

void Kruskal()
{
    int ans=0;
    for(int i=1; i<=m; i++)
        p[i]=i;
    sort(fuck+1,fuck+n+1,cmp);
    for(int i=1; i<=n; i++)
    {
        int x=find(fuck[i].u);
        int y=find(fuck[i].v);
        if(x!=y)
        {
            sum++;
            ans+=fuck[i].w;
            p[x]=y;
        }
    }
    if(sum==m)
        printf("%d\n",ans);
}

int main()
{
    while(~scanf("%d",&m),m)
    {
        sum=1;
        n=m*(m-1)/2;
        for(int i=1; i<=n; i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            fuck[i].u=a;
            fuck[i].v=b;
            fuck[i].w=c;
        }
        Kruskal();
    }
    return 0;
}

Problem HHDU 1879继续畅通工程

Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。 
 
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。 


当N为0时输入结束。
 
Output
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
 
Sample Input
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1

 
Sample Output
3
1


这题只是在上题的基础上增加一个变量而已,一开始盲目的在排序那里做改动,结果样例能过,提交上去却WA了,至于为什么这样不可以,我自己也没想清楚。把代码贴出来,望大神指教。

/*
ZXPxx 's source code for H
Memory: 0 KB		Time: 0 MS
Language: C++		Result: Wrong Answer

样例能过,提交却是wrong answer.

*/



#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=110000;
int p[maxn],m,n,sum;
struct node
{
    int u,v,w;
    bool z;
} fuck[maxn];

int cmp(node x,node y)
{
    if(x.z==1 && y.z==0)
        return x.z;
    else if(x.z==0 && y.z==1)
        return y.z;
    else
        return x.w<y.w;
}

int find(int x)
{
    return x==p[x]?p[x]:p[x]=find(p[x]);
}
void slove()
{
    int ans=0;
    for(int i=1; i<=m; i++)
        p[i]=i;
    sort(fuck+1,fuck+n+1,cmp);
    for(int i=1; i<=n; i++)
    {
        int x=find(fuck[i].u);
        int y=find(fuck[i].v);
        if(x!=y)
        {
            if(fuck[i].z==0)
                ans+=fuck[i].w;
            sum++;
            p[x]=y;
        }
    }
    if(sum==m)
        printf("%d\n",ans);
}

int main()
{
    while(~scanf("%d",&m),m)
    {
        sum=1;
        n=m*(m-1)/2;
        for(int i=1; i<=n; i++)
        {
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            fuck[i].u=a;
            fuck[i].v=b;
            fuck[i].w=c;
            fuck[i].z=d;
        }
        slove();
    }
    return 0;
}

思考了许久后可以说是恍然大悟,只需要在输入时把已经修好的路权值赋为0即可,立马改代码提交,AC了。


/*
ZXPxx 's source code for H
Memory: 1704 KB		Time: 795 MS
Language: C++		Result: Accepted
*/


#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=11000;
int p[maxn],m,n,sum;
struct node
{
    int u,v,w;
    bool z;
} fuck[maxn];

int cmp(node x,node y)
{
    return x.w<y.w;
}

int find(int x)
{
    return x==p[x]?p[x]:p[x]=find(p[x]);
}
void slove()
{
    int ans=0;
    for(int i=1; i<=m; i++)
        p[i]=i;
    sort(fuck+1,fuck+n+1,cmp);
    for(int i=1; i<=n; i++)
    {
        int x=find(fuck[i].u);
        int y=find(fuck[i].v);
        if(x!=y)
        {
            ans+=fuck[i].w;
            sum++;
            p[x]=y;
        }
    }
    if(sum==m)
        printf("%d\n",ans);
}

int main()
{
    while(~scanf("%d",&m),m)
    {
        sum=1;
        n=m*(m-1)/2;
        for(int i=1; i<=n; i++)
        {
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            fuck[i].u=a;
            fuck[i].v=b;
            if(d)
                fuck[i].w=0;    //只需要在此处做小小的改动即可
            else
                fuck[i].w=c;
        }
        slove();
    }
    return 0;
}

Problem  I HDU 1875畅通工程再续

Description
相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。
 
Input
输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。 
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。 
 
Output
每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.
 
Sample Input
2
2
10 10
20 20
3
1 1
2 2
1000 1000 
 
Sample Output
1414.2
oh!


这题比上面的题都要难写,只是由于以前做过,凭着记忆敲出来的,用的是prim算法,也AC了。

/*
ZXPxx 's source code for I
Memory: 1796 KB		Time: 15 MS
Language: C++		Result: Accepted
*/


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn=210;
#define inf 0x3f3f3f3f

double m[maxn][maxn],temp[maxn];
bool vis[maxn];
int n,t;
struct node
{
    int x,y;
} fuck[maxn];

void slove()
{
    double ans=0;
    for(int j=1; j<=n; j++)
        temp[j]=m[1][j];
    for(int i=1; i<=n; i++)
    {
        double min=inf;
        int k;
        for(int j=1; j<=n; j++)
            if(!vis[j] && min>temp[j])
            {
                k=j;
                min=temp[j];
            }
        if(min==inf)
        {
            printf("oh!\n");
            return;
        }
        vis[k]=1;
        ans+=min;
        for(int j=1; j<=n; j++)
            if(!vis[j] && temp[j]>m[j][k])
                temp[j]=m[j][k];
    }
    printf("%.1lf\n",ans*100);
}

double juli(int x, int y)
{
    return sqrt(double(x * x) + double(y * y));
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
            scanf("%d%d",&fuck[i].x,&fuck[i].y);
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                if(i==j) 
                    m[i][j]=0;
                else
                    m[i][j]=inf;
        for(int i=1; i<=n; i++)
        {
            vis[i]=0;
            for(int j=i+1; j<=n; j++)
            {
                m[i][j]=m[j][i]=juli(fuck[i].x - fuck[j].x, fuck[i].y-fuck[j].y);
//                   printf("m=%lf\n",m[i][j]);
                if(m[i][j]<10 || m[i][j]>1000)
                    m[i][j]=m[j][i] = inf;
            }
        }
        slove();
    }
    return 0;
}

Problem JUVA 11354Bond


据说这题是最后加上去的,用来防基神半小时AK的,比赛时果然起到了作用,没一个人动过。赛后百度题解,发现是(MST+LCA),好难啊 ORZ~至今仍然没有看懂,继续努力吧。

题解:(略)


去年的这个时候,对于最小生成树是完全不知所云,今年倒是好多了,对于这个专练,感觉并查集已经基本掌握了,只是最小生成树还只会最基本的,提升空间很大,总结下,最好的方法还是狂刷题。。。好了不多说,刷题去了……加油吧↖(^ω^)↗少年~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值