Ink on paper(HDU-7058)【最小生成树,小心超时】

这是一篇关于HDU-7058 'Ink on paper'问题的博客,主要讨论如何利用最小生成树算法(Prim或Kruskal)解决此题。文章提醒在实现算法时要注意常数优化和排序细节,避免超时。

标题:Ink on paper

---------------------------------------------------------------------------------------------------------------------------------------vjudge提交链接

在这里插入图片描述

题意:
——易理解,略。

官方题解:

——一道简单的最小生成树题,题面可以转化成在一个完全图上求最小生成树,直接使用Prim解决,复杂度n*n。常数较好的kruskal也可以通过,注意排序要写在结构体里面,写到外面超时

代码:(Kruskal)

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5005*5005;
ll x[5500],y[5500],f[5500];
struct Node{
	int u,v;
	ll w;
	bool operator <(const Node &b)const
	{
    	return w<b.w;
	}
}q[N];
int find(int x)
{
	if(x!=f[x])
    	f[x]=find(f[x]);
	return f[x];
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
    	int n;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
        	scanf("%lld %lld",&x[i],&y[i]);
    	int cnt=0;
    	for(int i=1;i<=n;i++)
    	{
        	for(int j=i+1;j<=n;j++)
        	{
            	q[++cnt].u=i;
            	q[cnt].v=j;
            	q[cnt].w=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
        	}
    	}
    	sort(q+1,q+1+cnt);
    	for(int i=1;i<=n;i++)    f[i]=i;
    	int total=n-1;
    	for(int i=1;i<=cnt;i++)
    	{
        	int tu=find(q[i].u);
        	int tv=find(q[i].v);
        	if(tu!=tv)
        	{
            	f[tv]=tu;
            	total--;
            	if(total==0)
            	{
                	printf("%lld\n",q[i].w);
                	break;
            	}
        	}
    	}
	}
	return 0;
}

代码:Prime

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll e[5500][5500],dis[5500],x[5500],y[5500];
int book[5500],n;
void init(){
	for(int i=1;i<=n;i++)    e[i][i]=0;
}
ll dist(int i,int j){
	return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
}
void Prim()
{
	int i,j,u,v;
	memset(book,0,sizeof(book));
	for(i=1;i<=n;i++)   dis[i]=e[1][i];
	book[1]=1;            //把1加入到树中
	ll mind,ans=0;
	for(i=1;i<=n-1;i++)
	{
    	mind=INF;u=-1;
    	for(j=1;j<=n;j++)
    	{
        	if(!book[j]&&mind>dis[j])
        	{
            	mind=dis[j];
            	u=j;
        	}
    	}
    	if(u==-1)    break;
    	ans=max(ans,dis[u]);
    	book[u]=1;
    	for(v=1;v<=n;v++)
    	{
        	if(!book[v]||e[u][v]<INF)
        	{
            	if(dis[v]>e[u][v])
                	dis[v]=e[u][v];
        	}
    	}
	}
	printf("%lld\n",ans);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)    
        	scanf("%lld %lld",&x[i],&y[i]);
    	init();
    	for(int i=1;i<=n;i++)
        	for(int j=i+1;j<=n;j++)
            	e[i][j]=e[j][i]=dist(i,j);
    	Prim();
	}
	return 0;
}

注: 用模板时,根据题意能优化时间的一定要优化,能优化空间的一定要优化,有些题就是卡这些小细节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值