首页 > 代码库 > 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号山。
输入输出样例
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
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)