首页 > 代码库 > SPFA+寻路(行路难,洛谷2832)

SPFA+寻路(行路难,洛谷2832)

啊啊啊这道难题总算是做出来了,首先是帅比浮云的题解发出来一下:http://www.cnblogs.com/fuyun-boy/p/5922742.html

原题目地址:https://www.luogu.org/problem/show?pid=2832

题目背景

小X来到了山区,领略山林之乐。在他乐以忘忧之时,他突然发现,开学迫在眉睫

题目描述

山区有n座山。山之间有m条羊肠小道,每条连接两座山,只能单向通过,并会耗费小X一定时间。

小X现在在1号山,他的目的是n号山,因为那里有火车站。

然而小X的体力是有限的。他每通过一条羊肠小道,就会变得更疲劳,导致他通过任意一条羊肠小道的时间都增加1。

输入输出格式

输入格式:

第一行两个数,n,m

第2行到第m+1行,每行3个数A,B,C,表示A、B之间有一条羊肠小道,可以让小X花费C的时间从A移动到B

输出格式:

两行 第一行一个数T,表示小X需要的最短时间

第二行若干个数,用空格隔开,表示小X的移动路线

例:1 4 2 5表示:小X从1号山开始,移动到4号山,再到2号山,最后到5号山。

输入输出样例

输入样例#1:
5 8
2 4 2
5 2 1
1 2 1
4 3 2
1 3 3
4 5 2
1 5 8
3 5 3
输出样例#1:
7
1 3 5 

说明

n<=10000, m<=200000

数据保证没有多条最短路径

【题解】

这道题就是最短路的变体,不过从起点到终点每多走一条边就要多加一点权值。

比如说原来的权值是6+7+9+3+5,之后的权值就是6+(7+1)+(9+2)+(3+3)+(5+4)了。

下面的这个是我写的代码。我的解决方法就是加上两个数组,一个是r,一个是tr。

d数组还是spfa一如既往的d数组,是除去这道题额外的条件的数组。

tr数组是补充数组(废话),d[i]+tr[i]表示从起点走到这个点的最小花费。

r[i]是按照从起点走到第i个节点花费d[i]+tr[i]的最短路径时,最后一次的增加值。

比如说上面的那个6+(7+1)+(9+2)+(3+3)+(5+4),表示一条路径,则这条路径终点节点的r数组的值是4。

因为走到这里最后一次加上的数字是4。

 pre数组不说了,帅比浮云说了很清楚。。。

#include <cstdio>
#include <cstring>
#include <queue>
#define mp make_pair
using namespace std;
int n,m,h;
struct edge
{
	int v,w;
	edge*next;
};
edge* link[10001];
int d[10001],r[10001],tr[10001],pre[10001]; 
bool v[10001];
void add(int u,int v,int w)
{
	edge* p=new edge;
	p->v=v;
	p->w=w;
	p->next=link[u];
	link[u]=p;
}
void del(edge* p)
{
	if(p!=NULL)
	{
		del(p->next);
		delete p;
	}
}
void spfa()
{
	queue<int>q;
	memset(d,0x3f,sizeof(d));
	d[1]=0;
	q.push(1);
	v[1]=true;
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		v[x]=false;
		for(edge* p=link[x];p!=0;p=p->next)
		{
			if(d[x]+tr[x]+p->w+r[x]<d[p->v]+tr[p->v])
			{
				d[p->v]=d[x]+p->w;
				tr[p->v]=tr[x]+r[x];
				r[p->v]=r[x]+1;
				pre[p->v]=x;
				if(v[p->v]==false)
				{
					v[p->v]=true;
					q.push(p->v);
				}
			}
		}
	}
}
void print(int n)
{
	if(n!=1)
		print(pre[n]);
	printf("%d ",n);
}
int main()
{
	int CO2,H2O,H2CO3;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&CO2,&H2O,&H2CO3);
		add(CO2,H2O,H2CO3);
	}
	spfa();
	printf("%d\n",d[n]+tr[n]);
	print(n);
	for(int i=1;i<=n;i++)
		del(link[i]);
	return 0;
}

祝各位NOIP2016 RP++ SCORE++

SPFA+寻路(行路难,洛谷2832)