累觉不爱POJ 1751Prim

原创 2014年09月19日 13:18:51

据说这是一道很裸的Prim模板题,网上的解释也很多。倔强的我在看了Prim生成原理后也决定自己动手写了。

STEP 1

已经相连的城市放在一个集合sele里,没选的放在队列remain里,然后每次都在remain里取出一个点,看看这个点与sele里的点哪个距离最小。输出。再把这个点归入sele。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define N 751
#define M 1001
int n, m;
struct node
{
	int x, y;
	double dis[N];
}city[N];
bool sele[N];
queue <int>remain;
int ans;
int main()
{
	int i, j, count;
	double min;
	while(~scanf("%d", &n))
	{
		count = 0;
		for(i = 1;i <= n;i++)
			scanf("%d%d", &city[i].x, &city[i].y);
		for(i = 1;i <= n;i++)
			for(j = 1;j <= n;j++)
				city[i].dis[j] = sqrt(pow(city[i].x-city[j].x,2)+pow(city[i].y-city[j].y,2));
		scanf("%d", &m);
		memset(city, 0, n);
		while(m--)
		{
			scanf("%d%d", &i, &j);
			sele[i] = 1;
			sele[j] = 1;
		}
		for(i = 1;i <= n;i++)
		{
			if(!sele[i])
				remain.push(i);
		}
		while(!remain.empty())
		{
			min = 1e5;
			j = remain.front();
			for(i = 1;i <= n;i++)
			{
				if(sele[i])
				{
					double t = city[i].dis[j];
					if(t < min)
					{
						min = t;
						ans = i;
					}
				}
			}
			sele[j] = 1;
			printf("%d %d\n", ans, j);
			remain.pop();
		}
	}
	return 0;
}
万万没想到,这不是prim啊!prim取的是在sele里的所有点向外连的所有线段里的最小线段。而我却是在remain里选点,显然不是滴……

而且这样的算法还会漏掉几条边。比如说1-3,2-5连起来了,1,2,3,5都被放在了sele里。如果刚好1-4连好,一切OK,那么1-3-4在一起,2-5在一起,形成了两个集合,但是它们之间却不连通呢!


STEP 2

愚蠢的我为了解决不连通的缺陷,特别设置了数组链表vector vet[n],把同在一个集合里的城市放在一个链表里,并且用order记录每个城市所在的vet序号,只有vet[1]被当作sele,当有其他vet里的城市被连进vet[1]时,该vet里的城市都被连vet[1]。由于找min是O(N^3)时间复杂度,TLE了。

进步在于这用了prim思想,确实找到了vet[1]里的所有点向外连的所有线段里的最小线段。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;
#define N 751
#define M 1001
int n, m;
struct node
{
	int x, y;
	double dis[N];
}city[N];
int order[N];
int main()
{
	vector<int>vet[N];
	int i, j, k, point;
	double min;
	while(~scanf("%d", &n))
	{
		for(i = 1;i <= n;i++)
			scanf("%d%d", &city[i].x, &city[i].y);
		for(i = 1;i <= n;i++)
			for(j = 1;j <= n;j++)
				city[i].dis[j] = sqrt(pow(city[i].x-city[j].x,2)+pow(city[i].y-city[j].y,2));
		scanf("%d", &m);
		for(i = 1;i <= n;i++)
			order[i] = 0;
		for(i = 1;i <= point;i++)
			while(!vet[i].empty())
				vet[i].pop_back();
		point = 1;
		int temp, big, change, len;
		if(m)
		{
			scanf("%d%d", &i, &j);
			order[i] = 1;
			order[j] = 1;
			vet[1].push_back(i);
			vet[1].push_back(j);
			m--;
			while(m--)
			{
				scanf("%d%d", &i, &j);
				if(!order[i] && !order[j])
				{
					point++;
					order[i] = point, order[j] = point;
					vet[point].push_back(i);
					vet[point].push_back(j);
				}
				else if(order[i] && !order[j])
				{
					order[j] = order[i];
					vet[order[i]].push_back(j);
				}
				else if(!order[i] && order[j])
				{
					order[i] = order[j];
					vet[order[j]].push_back(i);
				}
				else
				{
					temp = order[i]<order[j]?order[i]:order[j];
					big = max(order[i], order[j]);
					len = vet[big].size();
					for(k = len - 1;k >= 0;k--)
					{
						change = vet[big][k];
						order[change] = temp;
						vet[big].pop_back();
						vet[temp].push_back(change);
					}
				}
			}
		}
		else
		{
			order[1] = 1;
			vet[1].push_back(1);
		}
		int count = vet[1].size();
		int head, tail, num;
		while(count < n)
		{
			double min = 1e5;
			for(i = 0;i < count;i++)
			{
				num = vet[1][i];
				for(j = 1;j <= n;j++)
				{
					if(order[j] != 1)
					{
						if(city[num].dis[j] < min)
						{
							min = city[num].dis[j];
							head = num, tail = j;
						}
					}
				}
			}
			if(!order[tail])
			{
				order[tail] = 1;
				vet[1].push_back(tail);
			}
			else
			{
				num = order[tail];
				len = vet[num].size();
				for(k = len - 1;k >= 0;k--)
				{
					change = vet[num][k];
					vet[1].push_back(change);
					order[change] = 1;
					vet[num].pop_back();
				}
			}
			printf("%d %d\n", head, tail);
			count = vet[1].size();
		}
	}
	return 0;
}

STEP 3

其实只要把可能要连入的边排序完了一遍再依次找就行了,所以又改进:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;
#define N 751
#define M 1001
struct node
{
	int x, y;
	long long dis[N];
}city[N];
struct nod
{
	int x, y;
	long long dis;
}ans[N*N];
bool cmp(nod a, nod b)
{
	return a.dis < b.dis;
}
vector<int>vet[N];
int n, m, i, j, k, point, order[N];
int input()
{
	for(i = 1;i <= n;i++)
		scanf("%d%d", &city[i].x, &city[i].y);
	for(i = 1;i <= n;i++)
		for(j = 1;j <= n;j++)
			city[i].dis[j] = pow(city[i].x-city[j].x,2)+pow(city[i].y-city[j].y,2);
	scanf("%d", &m);
	for(i = 1;i <= n;i++)
		order[i] = 0;
	for(i = 1;i <= point;i++)
		while(!vet[i].empty())
			vet[i].pop_back();
}
int bute()
{
	int temp, big, change, len;
	if(!order[i] && !order[j])
	{
		point++;
		order[i] = point, order[j] = point;
		vet[point].push_back(i);
		vet[point].push_back(j);
	}
	else if(order[i] && !order[j])
	{
		order[j] = order[i];
		vet[order[i]].push_back(j);	
	}
	else if(!order[i] && order[j])
	{
		order[i] = order[j];
		vet[order[j]].push_back(i);
	}
	else
	{
		temp = order[i]<order[j]?order[i]:order[j];
		big = max(order[i], order[j]);
		len = vet[big].size();
		for(k = len - 1;k >= 0;k--)
		{
			change = vet[big][k];
			order[change] = temp;
			vet[big].pop_back();
			vet[temp].push_back(change);
		}
	}
}
int merge()
{
	scanf("%d%d", &i, &j);
	order[i] = 1;
	order[j] = 1;
	vet[1].push_back(i);
	vet[1].push_back(j);
	m--;
	while(m--)
	{
		scanf("%d%d", &i, &j);
		bute();
	}
}
int setsum()
{
	m = 0;
	for(i = 1;i <= n;i++)
		for(j = i;j <= n;j++)
			if(i != j && !(order[i] == 1 && order[j] == 1))
			{
				ans[m].x = i;
				ans[m].y = j;
				ans[m].dis = city[i].dis[j];
				m++;
			}
	sort(ans, ans + m, cmp);
}
int main()
{
	while(~scanf("%d", &n))
	{
		int v = 0;
		input();
		point = 1;
		if(!m)
		{
			order[1] = 1;
			vet[1].push_back(1);
		}	
		else
			merge();
		setsum();
		for(k = 0;k < m;k++)
		{
			i = ans[k].x, j = ans[k].y;
			if(order[i] == order[j])
				continue;
			bute();
			printf("%d %d\n", i, j, v = 1);
		}
		if(!v)
			printf("\n");
	}
	return 0;
}
竟然WA了....


STEP 4

经师兄指点,我的Prim理解错误,所以还是先看书吧( •̀ ω •́ )y ~~等我AC归来~~


万没想到,这不是prim啊
版权声明:本文为博主原创文章,未经博主允许不得转载。

微信开发一年,累觉不爱

我没想到,其实,我又有想到的,公司招我入来负责微信开发,到最后,虽说不上功成身退,但我也没有留下一个烂摊子、一个残局, 可能程序员做到这种地步,也算是一种悲哀了。        深有感触,深有...
  • jilongliang
  • jilongliang
  • 2014年04月23日 11:20
  • 911

poj 1062 昂贵的聘礼 Dijkstra算法,中等难度,,,内有测试数据,一道让我累觉不爱的题目

昂贵的聘礼 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 38474   Accepted: 11132 ...
  • Lionel_D
  • Lionel_D
  • 2015年02月21日 16:15
  • 1684

HDU1495:非常可乐(BFS)

Problem Description 大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而...
  • libin56842
  • libin56842
  • 2013年06月09日 21:05
  • 4108

hdu 1455 Sticks DFS 又是一个花样剪枝 ,累觉不爱

Problem Description George took sticks of the same length and cut them randomly until all parts beca...
  • Lionel_D
  • Lionel_D
  • 2015年03月20日 09:28
  • 681

hdu 3473 Minimum Sum 再来一波划分树,对划分树累觉不爱。

Problem Description You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you som...
  • Lionel_D
  • Lionel_D
  • 2015年02月07日 13:02
  • 651

2014开篇:为什么我不爱读书不爱学习

你是一个爱读书,爱学习,对自己的成长负责人的人吗? 正是因为学校中我们被问这样的问题次数太多了,所以我们才不会自己问自己这样的问题。 如果我们可以更早的对自己进行这样的提问,也许今天的我们大不同。 -...
  • zxcvmnbv
  • zxcvmnbv
  • 2014年01月11日 17:34
  • 884

如何看懂帕累托图

向左转|向右 帕累托图把不合格产品数或损失金额分成现象和原因等分类项目,并以大小顺序摆放的柱状图以及用折线表示其累计和的图。   上图是帕累托图画法教材。看帕累托图要点有三:...
  • joeyon
  • joeyon
  • 2014年12月04日 14:16
  • 1186

PMP笔记:质量管理中的帕累托图

帕累托图(Pareto chart)是以意大利经济学家V.Pareto的名字而命名的。帕累托图是石川质量管理的七个工具之一。帕累托图是一种按发生频率排序的特殊直方图。在质量管理中,可以通过帕累托图显示...
  • seagal890
  • seagal890
  • 2016年11月11日 15:20
  • 891

程序员每天累成狗,是为了什么

HI,想我了吗 了吗 了吗?自从上次情人节一别,我已经接近20天没更新文章了。 至于原因:是,办点其他私事,这一段压根没怎么联网,所以不太好意思,我也很想你们了。大家也不要问为什吗,辣么帅的人有什么...
  • xllily_11
  • xllily_11
  • 2017年03月11日 22:12
  • 12056

生而美者,若知之,若不知之,若闻之,若不闻之

【原文】天地与我并生,而万物与我为一。   [译文]天地和我共生,万物和我为一体。   人是天地的缩小版,天地是一个放大的人。天人本是合一的,人不要总是试图去改变天的布局和结构,他所需要甲做的只是...
  • zhaisharap
  • zhaisharap
  • 2014年02月28日 10:33
  • 2331
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:累觉不爱POJ 1751Prim
举报原因:
原因补充:

(最多只允许输入30个字)