# 无线通讯网
## 题目描述
国防部计划用无线网络连接若干个边防哨所。2 种不同的通讯技术用来搭建无线网络;
每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。
任意两个配备了一条卫星电话线路的哨所(两边都ᤕ有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过 $D$,这是受收发器的功率限制。收发器的功率越高,通话距离 $D$ 会更远,但同时价格也会更贵。
收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个 $D$。你的任务是确定收发器必须的最小通话距离 $D$,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。
## 输入格式
从 wireless.in 中输入数据第 1 行,2 个整数 $S$ 和 $P$,$S$ 表示可安装的卫星电话的哨所数,$P$ 表示边防哨所的数量。接下里 $P$ 行,每行两个整数 $x,y$ 描述一个哨所的平面坐标 $(x, y)$,以 km 为单位。
## 输出格式
输出 wireless.out 中
第 1 行,1 个实数 $D$,表示无线电收发器的最小传输距离,精确到小数点后两位。
## 样例 #1
### 样例输入 #1
```
2 4
0 100
0 300
0 600
150 750
```
### 样例输出 #1
```
212.13
```
## 提示
对于 $20\%$ 的数据:$P = 2,S = 1$
对于另外 $20\%$ 的数据:$P = 4,S = 2$
对于 $100\%$ 的数据保证:$1 ≤ S ≤ 100$,$S < P ≤ 500$,$0 ≤ x,y ≤ 10000$。
思路
这个题本质上就是考的最小生成树的俩个算法,主要就是难以找到突破点,由题目可以知道,只要俩哨点之间配备了卫星电话,就可以无视距离地进行通话,那么就相当于删除了一条边,如果至于一个卫星电话和没有卫星电话是一样的。那么如果具有了俩个以上的卫星电话,此时的情况就可以大致分为俩种,一种是俩个哨点之间本来就有联系,另一种是没有直接的联系,如果是第一种情况,那么此时最小距离应该为此时的第二大距离;如果是第二种情况,那么就要重新考虑新的树;
上图就是俩个卫星点的时候,那么此时必然要重新构建一个树。
如果此时再加入一个卫星点:
此时其实可以发现,如果把有卫星电话的哨点放在一堆,反正每个点之间也没有影响,那么就可以知道最小的距离应该选什么了;
代码
#include<stdio.h>
#include<math.h>
#define n 250001//注意大小
int s,p;
int a,b,x[510],y[510];//表示点
int f[501],num;
int k=0;
typedef struct//边,点,边长的结构体
{
int a,b;
double v;
} Edge;
//快速排列
void swap(Edge E[],int low,int high)
{
Edge temp;
temp = E[low];
E[low] = E[high];
E[high] = temp;
}
int fun(Edge E[],int low,int high)
{
double key;
Edge lowx;
lowx=E[low];
key=E[low].v;
while(low<high)
{
while(low<high && E[high].v>=key)
high--;
if(low<high)
swap(E,low,high);
while(low<high && E[low].v<=key)
low++;
if(low<high)
swap(E,low,high);
}
E[low]=lowx;
return low;
}
void quick_sort(Edge E[],int start,int end)
{
int pos;
if(start<end)
{
pos=fun(E,start,end);
quick_sort(E,start,pos-1);
quick_sort(E,pos+1,end);
}
}
//找根节点
int find(int x)
{
int x_root = x;
while(f[x_root]!=-1)
x_root = f[x_root];
return x_root;
}
//合并两个点
int hebing(int a,int b)
{
if( find(a) != find(b) )
{
f[find(b)]=find(a);
return 1;
}
else
return 0;
}
//计算点与点之间的距离
double weight(int x1,int y1,int x2,int y2)
{
return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
}
//kruskal
void L_kruskal(Edge E[])
{
int i;
for(i=1; i<=k; i++)
{
if( hebing(E[i].a,E[i].b) == 1)
{
hebing(E[i].a,E[i].b);
num--;
}
if(num == s)break;
}
printf("%.2lf", E[i].v);
}
int main()
{
int i;
Edge E[n];
scanf("%d%d",&s,&p);
for(i=1; i<=p; i++)
{
f[i]=-1;//初始化
scanf("%d%d",&a,&b);
x[i]=a;
y[i]=b;
}
for(i=1; i<=p; i++)
for(int j=i+1; j<=p; j++)
{
k++;
E[k].a=i;
E[k].b=j;
E[k].v=weight(x[i],y[i],x[j],y[j]);
}
quick_sort(E,1,k);
num=p;
L_kruskal(E);
return 0;
}
# 拆地毯
## 题目背景
还记得 NOIP 2011 提高组 Day1 中的铺地毯吗?时光飞逝,光阴荏苒,三年过去了。组织者精心准备的颁奖典礼早已结束,留下的则是被人们踩过的地毯。请你来解决类似于铺地毯的另一个问题。
## 题目描述
会场上有 n 个关键区域,不同的关键区域由 m 条无向地毯彼此连接。每条地毯可由三个整数 u、v、w 表示,其中 u 和 v 为地毯连接的两个关键区域编号,w 为这条地毯的美丽度。
由于颁奖典礼已经结束,铺过的地毯不得不拆除。为了贯彻勤俭节约的原则,组织者被要求只能保留 K 条地毯,且保留的地毯构成的图中,任意可互相到达的两点间只能有一种方式互相到达。换言之,组织者要求新图中不能有环。现在组织者求助你,想请你帮忙算出这 K 条地毯的美丽度之和最大为多少。
## 输入格式
第一行包含三个正整数 n、m、K。
接下来 m 行中每行包含三个正整数 u、v、w。
## 输出格式
只包含一个正整数,表示这 K 条地毯的美丽度之和的最大值。
## 样例 #1
### 样例输入 #1
```
5 4 3
1 2 10
1 3 9
2 3 7
4 5 3
```
### 样例输出 #1
```
22
```
## 提示
选择第 1、2、4 条地毯,美丽度之和为 10 + 9 + 3 = 22。
若选择第 1、2、3 条地毯,虽然美丽度之和可以达到 10 + 9 + 7 = 26,但这将导致关键区域 1、2、3 构成一个环,这是题目中不允许的。
1<=n,m,k<=100000
思路
就是正常找最小生成树,美丽度相当于边长,直接求和即可
代码
#include<stdio.h>
#define N 100001
int n,m,x,y,z,k;
int f[N],sum=0,num=0;
typedef struct
{
int a,b,v;
}Edge;
//快排
void swap(Edge E[],int low,int high)
{
Edge temp;
temp = E[low];
E[low] = E[high];
E[high] = temp;
}
int fun(Edge E[],int low,int high)
{
int key;
Edge lowx;
lowx=E[low];
key=E[low].v;
while(low<high)
{
while(low<high && E[high].v>=key)
high--;
if(low<high)
swap(E,low,high);
while(low<high && E[low].v<=key)
low++;
if(low<high)
swap(E,low,high);
}
E[low]=lowx;
return low;
}
void quick_sort(Edge E[],int start,int end)
{
int pos;
if(start<end)
{
pos=fun(E,start,end);
quick_sort(E,start,pos-1);
quick_sort(E,pos+1,end);
}
}
int find(int i)
{
int i_root = i;
while(f[i_root]!=-1)
i_root = f[i_root];
return i_root;
}
int hebing(int a,int b)
{
if( find(a) != find(b) )
{
f[find(b)]=find(a);
return 1;
}
else
return 0;
}
void L_kruskal(Edge E[])
{
for(int i=m;i>=1;i--)
{
if( hebing(E[i].a,E[i].b) == 1)
{
hebing(E[i].a,E[i].b);
num++;
sum+=E[i].v;
}
if(num == k)break;
}
printf("%d\n",sum);
}
int main()
{
Edge E[N];
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&E[i].a,&E[i].b,&E[i].v);
quick_sort(E,1,m);
for(int i=1;i<=n;i++)
f[i]=-1;
L_kruskal(E);
return 0;
}
# [USACO07DEC]Building Roads S
## 题目描述
Farmer John had just acquired several new farms! He wants to connect the farms with roads so that he can travel from any farm to any other farm via a sequence of roads; roads already connect some of the farms.
Each of the N (1 ≤ N ≤ 1,000) farms (conveniently numbered 1..N) is represented by a position (Xi, Yi) on the plane (0 ≤ Xi ≤ 1,000,000; 0 ≤ Yi ≤ 1,000,000). Given the preexisting M roads (1 ≤ M ≤ 1,000) as pairs of connected farms, help Farmer John determine the smallest length of additional roads he must build to connect all his farms.
给定 $n$ 个点的坐标,第 $i$ 个点的坐标为 $(x_i,y_i)$,这 $n$ 个点编号为 $1$ 到 $n$。给定 $m$ 条边,第 $i$ 条边连接第 $u_i$ 个点和第 $v_i$ 个点。现在要求你添加一些边,并且能使得任意一点都可以连通其他所有点。求添加的边的总长度的最小值。
## 输入格式
\* Line 1: Two space-separated integers: N and M
\* Lines 2..N+1: Two space-separated integers: Xi and Yi
\* Lines N+2..N+M+2: Two space-separated integers: i and j, indicating that there is already a road connecting the farm i and farm j.
第一行两个整数 $n,m$ 代表点数与边数。
接下来 $n$ 行每行两个整数 $x_i,y_i$ 代表第 $i$ 个点的坐标。
接下来 $m$ 行每行两个整数 $u_i,v_i$ 代表第 $i$ 条边连接第 $u_i$ 个点和第 $v_i$ 个点。
## 输出格式
\* Line 1: Smallest length of additional roads required to connect all farms, printed without rounding to two decimal places. Be sure to calculate distances as 64-bit floating point numbers.
一行一个实数代表添加的边的最小长度,要求保留两位小数,为了避免误差, 请用 $64$ 位实型变量进行计算。
## 样例 #1
### 样例输入 #1
```
4 1
1 1
3 1
2 3
4 3
1 4
```
### 样例输出 #1
```
4.00
```
## 提示
### 数据规模与约定
对于 $100\%$ 的整数,$1 \le n,m \le 1000$,$1 \le x_i,y_i \le 10^6$,$1 \le u_i,v_i \le n$。
### 说明
Translated by 一只书虫仔。
思路
跟上个题目没啥大的区别,先把有的节点连起来,然后就是求出每个点之间的距离,排列好,然后相加得到结果
代码
#include<stdio.h>
#include<math.h>
#define BER 1000001
int n,m,p,q,k;
double x[1001],y[1001];
int f[1001],num;
double sum=0;
typedef struct
{
int a,b;
double v;
}Edge;
void swap(Edge E[],int low,int high)
{
Edge temp;
temp = E[low];
E[low] = E[high];
E[high] = temp;
}
int fun(Edge E[],int low,int high)
{
double key;
Edge lowx;
lowx=E[low];
key=E[low].v;
while(low<high)
{
while(low<high && E[high].v>=key)
high--;
if(low<high)
swap(E,low,high);
while(low<high && E[low].v<=key)
low++;
if(low<high)
swap(E,low,high);
}
E[low]=lowx;
return low;
}
void quick_sort(Edge E[],int start,int end)
{
int pos;
if(start<end)
{
pos=fun(E,start,end);
quick_sort(E,start,pos-1);
quick_sort(E,pos+1,end);
}
}
int find(int i)
{
int i_root = i;
while(f[i_root]!=-1)
i_root = f[i_root];
return i_root;
}
int hebing(int a,int b)
{
if( find(a) != find(b) )
{
f[find(b)]=find(a);
return 1;
}
else
return 0;
}
double weight(double x1,double y1,double x2,double y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void L_kruskal(Edge E[])
{
for(int i=1;i<=k;i++)
{
if( find(E[i].a) != find(E[i].b) )
{
hebing(E[i].a,E[i].b);
num++;
sum+=E[i].v;
}
if(num == n-1)break;
}
printf("%.2lf",sum);
}
int main()
{
Edge E[BER];
scanf("%d%d",&n,&m);
num=m;
for(int i=1;i<=n; i++)
{
f[i]=-1;
scanf("%lf%lf",&x[i],&y[i]);
}
k=0;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
k++;
E[k].a=i;E[k].b=j;
E[k].v=weight(x[i],y[i],x[j],y[j]);
}
quick_sort(E,0,k);
while(m--)
{
scanf("%d%d",&p,&q);
hebing(p,q);
}
L_kruskal(E);
return 0;
}