• 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
    ",sum);
    	return 0;
    }
    
  • 相关阅读:
    Git在商业项目中的使用流程
    EventBus中观察者模式的应用
    作业三——安卓系统文件助手APP原型设计
    视频剪辑软件的调研——万兴神剪手、视频编辑王、爱剪辑
    18-10-31 Scrum Meeting 3
    myapp——自动生成小学四则运算题目的命令行程序(侯国鑫 谢嘉帆)
    一个「学渣」从零开始的Web前端自学之路
    Vue一个案例引发「内容分发slot」的最全总结
    Vue CLI 3.0脚手架如何在本地配置mock数据
    Vue一个案例引发「动画」的使用总结
  • 原文地址:https://www.cnblogs.com/kalginamiemeng/p/Exam20190817T1.html
Copyright © 2020-2023  润新知