POJ-2457 SPFA+路径记录

0 篇文章 0 订阅

http://poj.org/problem?id=2457

Part Acquisition部分收购

题意:
    奶牛们被送往太空去执行一个任务:为它们的农场收购一台挤奶机器。它们正通过
一个含有N颗行星的星系。(1<=N<=50 000),每颗行星都是一个交易站。
    奶牛们决定了使用 K种(1<=K<=1000)种商品在这些星球中进行交易。这些星球没
有发展货币,所以星球交易都是在货易系统下工作的:所有的交易都是用一种货物交换
另外一种货物。假设互相交易的两种货物是不同的。
    奶牛们从地球出发,带着一罐高品质的干草(货物1号),它们想最终用罐干草换回
一台挤奶机器(货物K号)。你们经常喝奶牛们的牛奶,奶牛们请你帮忙:确定如何与
该星系所有星球交易,最后得到得到货物K号,奶牛们要你构造最好的交易序列。如果无
论如何都不可能最后换得货物K号,那么输出“-1”。

Input  输入
* 第一行:N和K


* 第 2..N+1行: 第 i+1 行 包含两个整数  ai 和 bi, 代表星球i用货物ai去换取货物bi. 

Output 输出
* 第一行: 一个整数T,即为用货物1号换得货物k号的最少交换序列。(或者 -1。如果无法
换得货物K号 ). 

* 第2..T+1行: 列出交换序列中每个货物的编号. 

Sample Input 

 6 5
 1 3
 3 2

 2 3
 3 1
 2 5
 5 4 

Sample Output 
  4
 1
 3
 2

 5 

把货物当做节点,星球当做节点间的权为1的边,而这题我花的时间大部分在路径的记录上


思路:先建一个数组pre[MAXVEX],松弛操作时,便将当前节点i的前驱节点j记下pre[i]=j。

因为SPFA已证明最短路上的起点到任意一点的路都为最短。所以SPFA后,得出的数组pre中

的元素j,便是起点到节点i最短路径上的前驱...(有点难表达....image...image)


最后的路径输出(需要注意),可以新建一个数组读入再输入,或递归输出...

附:SPFA优化:SLF和LLL:SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队尾。 LLL:Large Label Last 策略,设队首元素为i,队列中所有dist值的平均值为x,若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将i出对进行松弛操作。 SLF 可使速度提高 15 ~ 20%;SLF + LLL 可提高约 50%。 在实际的应用中SPFA的算法时间效率不是很稳定,为了避免最坏情况的出现,通常使用效率更加稳定的Dijkstra算法。

代码如下:

#include<cstdio>
#include<cstring>

using namespace std;

#define INF 99999
#define MAXVEX 1005
#define MAXEDGE 50005
struct EdgeType{
	int begin;
	int end;
	int next;
}edge[MAXEDGE];		/*数组实现邻接表*/ 

int n,k;		/*n个星球,k个商品。商品看作节点,星球看作权值为1的边*/ 
int numE=0;
int last[MAXVEX],step[MAXVEX];		//step记录每个星球的最小交换次数 
int pre[MAXVEX];		//previous point:每个节点的上一个 

void read(){
	int i;
	scanf("%d %d",&n,&k);
	memset(last,0,sizeof(last));
	for (i=1;i<=n;i++){
		int a,b;
		numE++;
		scanf("%d %d",&a,&b);
		edge[numE].begin=a;edge[numE].end=b;
		edge[numE].next=last[a];last[a]=numE;
	}
}

void spfa(){
	bool v[MAXVEX]={};
	int que[MAXVEX],head=1,tail=2;
	int i;
	for (i=1;i<=k;i++) step[i]=INF;
	v[1]=true;que[head]=1;step[1]=1;
	
	while (head!=tail){
		int x=que[head],l;
		for (l=last[x];l>0;l=edge[l].next){
			int y=edge[l].end;
			if (step[x]+1<step[y]){
				step[y]=step[x]+1;
				pre[y]=edge[l].begin;		/*记录每个点的前驱*/
				if (!v[y]){
					if (step[y]<step[x]) que[head--]=y;		/*SLF优化*/
					else {
						que[tail]=y;
						tail++;if (tail==MAXVEX)tail=1;
					}
					v[y]=true;
				}
			}
		}/*for*/
		head++;if (head==MAXVEX)head=1;
		v[x]=false;
	}/*while*/
}

void print_way(int now){
	int ans;
	if (now==1) ans=1;	
	else {
		print_way(pre[now]);
		ans=now;
	}
	printf("%d\n",ans); 
}

int main(){
	read();
	spfa();
	if (step[k]!=INF){
		printf("%d\n",step[k]); 
		print_way(k);
	}else printf("-1");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值