20190817-T1-LOJ6322「雅礼国庆 2017 Day6」Star Way To Heaven

写这篇题解是因为作者太蒻已经忘了最小生成树了。

<题面>

这个题还真是想不到最小生成树。

$80\%$算法

复杂度:$\Theta(k^2 \log N )$

用了二分答案(明显答案具有单调性)

然后$k^2$暴力判断是否合法。

可以得到80分。

$100\%$算法

复杂度:$\Theta(k^2)$

考虑上面的暴力判断,

如何判断呢?要搜点距,$dfs$

然后我们就可以得到一些东西。

假设现在得到了答案是$ans$

我们考虑它的特性。

在每一个点上以$ans$为半径画圆

那么,一定有一条边上的两条圆是相切的。

如果$ans$变小,那么一定有一个更优解。

如果$ans$更大,那么圆一定会相交导致路径不连续。

我们再找找性质,

发现这两个圆一定在上边界到下边界的路径上,且是路径上最长的边,这也是导致上文路径不连续的原因。

对于一个点,那个圆一定出现在与它相连的最短边上,

因为如果有更长边,更长边会充当一个三角形的最长边,导致路径会受更短的一条边约束。

于是有最小生成树(我考试肯定想不出来QAQ)

在找最小生成树时,就一定可以保证找到加入树的边一定是上文的最短边。

于是直接套用$Prim$顺便维护到下边界的距离,复杂度$\Theta(k^2)$

我本来想优化,于是想用堆:$\Theta(k^2) \Rightarrow \Theta(e \log k)$

于是边数$e=k^2$

$\Theta(k^2) \Rightarrow \Theta(k^2 \log k)$//当我没说

这时有一个问题,不能建图,空间复杂度不可承受。

于是需要使用欧几里得距离最小生成树。

你可能肯定会想,这又是什么玩意?

其实就是最小生成树,只是不建边而是去用点直接计算距离。

所以愉快的AC了

#include <iostream>
#include <cstdio>
#include <cmath>
#define N 6060
#define LF double

using namespace std;

int pn,hei;
struct x_y{
	LF x,y;
}ps[5*N];
LF dis[5*N],ans=0;
bool is_v[N];
inline LF len(const x_y a,const x_y b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void prim(){
	for(int i=1;i<=pn;i++){
		dis[i]=hei-ps[i].y;
	}
	for(int i=1;i<=pn+1;i++){
		int x=0;
		for(int j=1;j<=pn+1;j++){
			if((!is_v[j])&&(x==0||dis[j]<dis[x])){
				x=j;
			}
		}
		ans=max(ans,dis[x]);
		if(x==pn+1){//这里是必写的,因为这个意味着更新结束
			return ;
		}
		is_v[x]=1;
		int j;
		for(j=1;j<=pn;j++){
			{
				dis[j]=min(dis[j],len(ps[j],ps[x]));
			}
		}
		dis[pn+1]=min(dis[pn+1],ps[x].y);
	}
}
int main(){
	int x,y;
	scanf("%*d%d%d",&hei,&pn);
	for(int i=1;i<=pn;i++){
		scanf("%d%d",&x,&y);
		ps[i].x=x;
		ps[i].y=y;
	}
	dis[pn+1]=hei;
	prim();
	printf("%.9lf",ans/2);
}

码量也并不大。

这里顺便写一下两个最小生成树的板板。

1.Kruskal

/*****
Kruskal
*****/
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm> 
using namespace std;
bool b[101];
int answer,ans,n,t,f[1001];
struct node
{
	int fr,to,ti;
}a[10001];
bool cmp(node xx,node yy)
{
	return xx.ti<yy.ti;
}
int find(int x)
{
	if (f[x]==x) return x;
	 else return f[x]=find(f[x]);
} 
void merge(int x,int y)
{
	int xx=find(x); 
	int yy=find(y);
	if (xx<yy) f[xx]=f[yy];
	 else f[yy]=f[xx];
}
int main()
{
	scanf("%d",&n);
	for (int i=1; i<=n; ++i) f[i]=i;
	for (int i=1; i<=n; ++i)
	 for (int j=1; j<=n; ++j)
	  {
	  		int x;
	  		scanf("%d",&x);
	  		if (x!=0) {a[++t]=(node){i,j,x};}
	  }
	 int k=0;
     sort(a+1,a+t+1,cmp);
     for (int i=1; i<=t; ++i)
     {
     	if (find(a[i].fr)!=find(a[i].to)) {//不在同一个集合中 
		   merge(a[i].fr,a[i].to);//合并
     	   ans+=a[i].ti;//记录最小生成值
     	   k++;//记录边数
     	 } 
     	if (k==n-1) break;//一棵树,n个点,n-1条边
     }
	 printf("%d",ans);
}

 

2.Prim

/******
Prime
******/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int con[101][101],dis[101],num,a;
int main(){
	cin>>num;
	long long sum=0,min=0x7fffffff;
	memset(dis,0x7f,sizeof(dis));
	for(int i=1;i<=num;i++){
		for(int j=1;j<=num;j++){
			scanf("%d",&con[i][j]);
		}
	}
	dis[1]=0;
	for(int i=1;i<=num;i++)
		dis[i]=con[1][i];
	for(int i=1;i<=num;i++){
		min=0x7f7f7f7f;
		for(int j=1;j<=num;j++){
			if(dis[j]!=0&&dis[j]<min){
				min=dis[j];//cout<<"i"<<i<<"min"<<min<<endl;
				a=j;//cout<<"a"<<a<<endl;
			}
		}
		sum+=dis[a];
		dis[a]=0;
		for(int j=1;j<=num;j++)
			if(dis[j]>con[a][j])
				dis[j]=con[a][j];
	}
	printf("%d\n",sum);
	return 0;
}

 

转载于:https://www.cnblogs.com/kalginamiemeng/p/Exam20190817T1.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本项目是一个基于SpringBoot开发的华府便利店信息管理系统,使用了Vue和MySQL作为前端框架和数据库。该系统主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的Java学习者,包含项目源码、数据库脚本、项目说明等,有论文参考,可以直接作为毕设使用。 后台框架采用SpringBoot,数据库使用MySQL,开发环境为JDK、IDEA、Tomcat。项目经过严格调试,确保可以运行。如果基础还行,可以在代码基础之上进行改动以实现更多功能。 该系统的功能主要包括商品管理、订单管理、用户管理等模块。在商品管理模块中,可以添加、修改、删除商品信息;在订单管理模块中,可以查看订单详情、处理订单状态;在用户管理模块中,可以注册、登录、修改个人信息等。此外,系统还提供了数据统计功能,可以对销售数据进行统计和分析。 技术实现方面,前端采用Vue框架进行开发,后端使用SpringBoot框架搭建服务端应用。数据库采用MySQL进行数据存储和管理。整个系统通过前后端分离的方式实现,提高了系统的可维护性和可扩展性。同时,系统还采用了一些流行的技术和工具,如MyBatis、JPA等进行数据访问和操作,以及Maven进行项目管理和构建。 总之,本系统是一个基于SpringBoot开发的华府便利店信息管理系统,使用了Vue和MySQL作为前端框架和数据库。系统经过严格调试,确保可以运行。如果基础还行,可以在代码基础之上进行改动以实现更多功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值