2月5日刷题总结

P1396 营救

题目背景

“咚咚咚……”“查水表!”原来是查水表来了,现在哪里找这么热心上门的查表员啊!小明感动得热泪盈眶,开起了门……

题目描述

妈妈下班回家,街坊邻居说小明被一群陌生人强行押上了警车!妈妈丰富的经验告诉她小明被带到了 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,tn。且从 ss 出发一定能到达 tt 区。


样例输入输出 1 解释

小明的妈妈要从 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
*/

P1195 口袋的天空

题目背景

小杉坐在教室里,透过口袋一样的窗户看口袋一样的天空。

有很多云飘在那里,看起来很漂亮,小杉想摘下那样美的几朵云,做成棉花糖。

题目描述

给你云朵的个数 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,YN,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");//非联通
}

P4047 [JSOI2010]部落划分

题目描述

聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗。只是,这一切都成为谜团了——聪聪根本就不知道部落究竟是如何分布的。

不过好消息是,聪聪得到了一份荒岛的地图。地图上标注了 nn 个野人居住的地点(可以看作是平面上的坐标)。我们知道,同一个部落的野人总是生活在附近。我们把两个部落的距离,定义为部落中距离最近的那两个居住点的距离。聪聪还获得了一个有意义的信息——这些野人总共被分为了 kk 个部落!这真是个好消息。聪聪希望从这些信息里挖掘出所有部落的详细信息。他正在尝试这样一种算法:

对于任意一种部落划分的方法,都能够求出两个部落之间的距离,聪聪希望求出一种部落划分的方法,使靠得最近的两个部落尽可能远离。

例如,下面的左图表示了一个好的划分,而右图则不是。请你编程帮助聪聪解决这个难题。

2月5日刷题总结_第1张图片

输入格式

输入文件第一行包含两个整数 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≤kn≤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

你可能感兴趣的:(预备役每日总结,图论,数据结构,c语言,算法)