“咚咚咚……”“查水表!”原来是查水表来了,现在哪里找这么热心上门的查表员啊!小明感动得热泪盈眶,开起了门……
妈妈下班回家,街坊邻居说小明被一群陌生人强行押上了警车!妈妈丰富的经验告诉她小明被带到了 tt 区,而自己在 ss 区。
该市有 mm 条大道连接 nn 个区,一条大道将两个区相连接,每个大道有一个拥挤度。小明的妈妈虽然很着急,但是不愿意拥挤的人潮冲乱了她优雅的步伐。所以请你帮她规划一条从 ss 至 tt 的路线,使得经过道路的拥挤度最大值最小。
第一行有四个用空格隔开的 nn,mm,ss,tt,其含义见【题目描述】。
接下来 mm 行,每行三个整数 u, v, wu,v,w,表示有一条大道连接区 uu 和区 vv,且拥挤度为 ww。
两个区之间可能存在多条大道。
输出一行一个整数,代表最大的拥挤度。
输入 #1复制
3 3 1 3
1 2 2
2 3 1
1 3 3
输出 #1复制
2
对于 30\%30% 的数据,保证 n\leq 10n≤10。
对于 60\%60% 的数据,保证 n\leq 100n≤100。
对于 100\%100% 的数据,保证 1 \leq n\leq 10^41≤n≤104,1 \leq m \leq 2 \times 10^41≤m≤2×104,w \leq 10^4w≤104,1 \leq s, t \leq n1≤s,t≤n。且从 ss 出发一定能到达 tt 区。
小明的妈妈要从 1 号点去 3号点,最优路线为 1->2->3。
思路:最小生成树模板题,判断条件改动一下即可(当s和t联通即得到营救成功)
#include
#include
#include
#include
#define inf 99999999
struct node
{
int u,v,w;
}e[20005];
int f[10005];
int cmp(const void*p1,const void *p2)//快速排序的回调函数
{
return ((struct node *)p1)->w-((struct node *)p2)->w;
}
//并查集
void init(int n)
{
for(int i=0;i<=n;i++)
{
f[i]=i;
}
}
int find(int x)
{
return x==f[x]?x:f[x]=find(f[x]);
}
int cb(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
{
f[x]=y;
return 1;
}
return 0;
}
//主函数
int main()
{
int n,m,s,t,t1,t2,t3,ans=0;
scanf("%d%d%d%d",&n,&m,&s,&t);
init(n);
for(int i=1;i<=m;i++)
{
e[i].w=inf;//设置初始值,用于判断重边
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&t1,&t2,&t3);
e[i].u=t1,e[i].v=t2,e[i].w=t3;
if(e[i].w>t3)//重边取小的那个
{
e[i].u=t1;
e[i].v=t2;
e[i].w=t3;
}
}
qsort(e+1,m,sizeof(node),cmp);//排序
for(int i=1;i<=m;i++)
{
if(cb(e[i].u,e[i].v)==1)
{
ans=e[i].w;//反复更新ans
}
if(find(s)==find(t))break;//如果s和t已经联通,就结束
}
printf("%d",ans);
}
/*
3 3 1 3
1 2 5
2 3 1
1 3 3
*/
小杉坐在教室里,透过口袋一样的窗户看口袋一样的天空。
有很多云飘在那里,看起来很漂亮,小杉想摘下那样美的几朵云,做成棉花糖。
给你云朵的个数 NN,再给你 M个关系,表示哪些云朵可以连在一起。
现在小杉要把所有云朵连成 K个棉花糖,一个棉花糖最少要用掉一朵云,小杉想知道他怎么连,花费的代价最小。
第一行有三个数 N,M,KN,M,K。
接下来 MM 行每行三个数 X,Y,LX,Y,L,表示 XX 云和 YY 云可以通过 LL 的代价连在一起。
对每组数据输出一行,仅有一个整数,表示最小的代价。
如果怎么连都连不出K 个棉花糖,请输出 No Answer。
输入 #1复制
3 1 2
1 2 1
输出 #1复制
1
对于 30\%30% 的数据,1 \le N \le 1001≤N≤100,1\le M \le 10^31≤M≤103;
对于 100\%100% 的数据,1 \le N \le 10^31≤N≤103,1 \le M \le 10^41≤M≤104,1 \le K \le 101≤K≤10,1 \le X,Y \le N1≤X,Y≤N,0 \le L<10^40≤L<104。
思路:最小生成树的题,要求生成k棵树,n个结点n-1条边,为一棵树,n个结点n-2条边为俩棵树,所以n个结点n-k条边为k棵树,所以我们的结束条件为cnt==n-k
#include
#include
#include
#include
struct node
{
int u,v,w;
}e[10005];
int f[1005];
int cmp(const void*p1,const void *p2)//回调函数
{
return ((node *)p1)->w-((node *)p2)->w;
}
void init(int n)//用于父亲数组的初始化
{
for(int i=0;i<=n;i++)
{
f[i]=i;
}
}
//并查集
int find(int x)
{
return x==f[x]?x:f[x]=find(f[x]);
}
int cb(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
{
f[x]=y;
return 1;
}
return 0;
}
int main()
{
int N,M,K,t1,t2,t3,cnt,ans=0;
scanf("%d%d%d",&N,&M,&K);
init(N);
for(int i=1;i<=M;i++)
{
scanf("%d%d%d",&t1,&t2,&t3);
e[i].u=t1,e[i].v=t2,e[i].w=t3;
}
qsort(e+1,M,sizeof(node),cmp);//快速排序
for(int i=1;i<=M;i++)
{
if(cb(e[i].u,e[i].v)==1)//不在同一集合
{
cnt++;//边的个数
ans+=e[i].w;//权值累加
}
if(cnt==N-K)break;
}
if(cnt==N-K)printf("%d",ans);
else printf("No Answer");//非联通
}
聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗。只是,这一切都成为谜团了——聪聪根本就不知道部落究竟是如何分布的。
不过好消息是,聪聪得到了一份荒岛的地图。地图上标注了 nn 个野人居住的地点(可以看作是平面上的坐标)。我们知道,同一个部落的野人总是生活在附近。我们把两个部落的距离,定义为部落中距离最近的那两个居住点的距离。聪聪还获得了一个有意义的信息——这些野人总共被分为了 kk 个部落!这真是个好消息。聪聪希望从这些信息里挖掘出所有部落的详细信息。他正在尝试这样一种算法:
对于任意一种部落划分的方法,都能够求出两个部落之间的距离,聪聪希望求出一种部落划分的方法,使靠得最近的两个部落尽可能远离。
例如,下面的左图表示了一个好的划分,而右图则不是。请你编程帮助聪聪解决这个难题。
输入文件第一行包含两个整数 nn 和 kk,分别代表了野人居住点的数量和部落的数量。
接下来 nn 行,每行包含两个整数 xx,yy,描述了一个居住点的坐标。
输出一行一个实数,为最优划分时,最近的两个部落的距离,精确到小数点后两位。
输入 #1复制
4 2
0 0
0 1
1 1
1 0
输出 #1复制
1.00
输入 #2复制
9 3
2 2
2 3
3 2
3 3
3 5
3 6
4 6
6 2
6 3
输出 #2复制
2.00
对于 100\%100% 的数据,保证 2 \leq k \leq n \leq 10^32≤k≤n≤103,0 \leq x, y \leq 10^40≤x,y≤104。
思路:同P1396类似,求最小生成树,k个部落,即k棵最小生成树,k+1条边即为k个部落最近部落的最小距离,利用克鲁斯卡尔算法生成最小树,n-1条边为1棵树,n-k条边即k棵树,我们需要n-k+1条边的权值。
#include
#include
#include
#include
#include
using namespace std;
int x[1005],y[1005],f[1005],cnt=0;
struct node
{
int x,y;
long double dis;
}e[1005*1005];//储存各个顶点的边的权值
bool cmp(node a,node b)//sort函数根据dis排序
{
return a.dis