1. 程式人生 > >分層圖最短路(魔改SPFA)

分層圖最短路(魔改SPFA)

上週考了道這個因為段考到現在才改完這個 = =

這類問題嘛......算了我先放題目 就比如這個

很顯然問題都是最短路 然後中間可以跳邊走的那種

然後考場上我愣是想到了dp.....

好吧後來我也是在這個基礎上改的 不過這個就是叫分層圖最短路....

做法一:拆點 能免費幾條路就把一個點拆成多少個點 當然還要加1 (原始的) 連的話就是 x 和 y + n 連一個費用為 0 的邊 x 和 y 連一個費用為費用的邊 如果無向圖別忘了反過來

做法二:就像dp一樣 dis[p][k] 為 到達 p 號點 使用 k 條免費路時最小的 dis 值 然後設 p 點到達 b 點 推導就是這樣個東西

dis[b][k] = min(dis[b][k],min(dis[p][k] + v,dis[p][k - 1])) 這個應該分兩個 但我懶得打了於是就合併了

當然遇到最短路 卡SPFA注意啦 然後我有魔改SPFA 完全不怕!好吧就是加堆啦 = =

其實原本這堆超醜的 如下

inline void push(int p,int k)
{
	++tot;
	heap[tot][0] = p;
	heap[tot][1] = k;
	o[p][k] = 1;
	int now = tot;
	while (now > 1 && dis[heap[now][0]][heap[now][1]] < dis[heap[now >> 1][0]][heap[now >> 1][1]])
	swap(heap[now],heap[now >> 1]),now >>= 1;
}
inline void pop(int &p,int &k)
{
	p = heap[1][0];
	k = heap[1][1];
	o[p][k] = 0;
	heap[1][0] = heap[tot][0];
	heap[1][1] = heap[tot][1];
	--tot;
	int now = 1;
	while (now << 1 <= tot && dis[heap[now][0]][heap[now][1]] > dis[heap[now << 1][0]][heap[now << 1][1]] ||
			now << 1 < tot && dis[heap[now][0]][heap[now][1]] > dis[heap[now << 1 | 1][0]][heap[now << 1 | 1][1]])
	{
		int nxt = now << 1;
		if (nxt < tot && dis[heap[nxt | 1][0]][heap[nxt | 1][1]] < dis[heap[nxt][0]][heap[nxt][1]]) ++nxt;
		swap(heap[now],heap[nxt]);
	}
}

然後中間判斷距離的就放judge裡面了 看起來好多了 下放程式碼

#include <algorithm>
#include <cstring>
#include <cstdio>
#define MAXN 10010
#define MAXM 100010
using namespace std;
struct edge {
	int ne,to,v;
} e[MAXM];
struct queue {
	int nod,ed;
} heap[MAXM];
int first[MAXN],dis[MAXN][22];
int tot;
short o[MAXN][22];
inline short judge(queue x,queue y) {return dis[x.nod][x.ed] > dis[y.nod][y.ed];}
inline int r()
{
	char q = getchar(); int x = 0,y = 0;
	while (q < '0' && q != '-' || q > '9') q = getchar();
	if (q == '-') ++ y,q = getchar();
	while ('0' <= q && q <= '9')
		x = (x << 3) + (x << 1) + q - (3 << 4),q = getchar();
	return y ? -x : x;
}
inline void add(int x,int y,int z)
{
	e[++tot].ne = first[x];
	e[tot].to = y;
	e[tot].v = z;
	first[x] = tot;
}
inline void push(int p,int k)
{
	heap[++tot].ed = k;
	heap[tot].nod = p;
	o[p][k] = 1;
	int now = tot;
	while (now > 1 && judge(heap[now >> 1],heap[now]))
		swap(heap[now],heap[now >> 1]),now >>= 1;
}
inline void pop(int &p,int &k)
{
	p = heap[1].nod;
	k = heap[1].ed;
	o[p][k] = 0;
	heap[1] = heap[tot--];
	int now = 1;
	while (now << 1 <= tot && judge(heap[now],heap[now << 1]) ||
			now << 1 < tot && judge(heap[now],heap[now << 1 | 1]))
	{
		int nxt = now << 1;
		if (nxt < tot && judge(heap[nxt],heap[nxt | 1])) ++nxt;
		swap(heap[now],heap[nxt]),now = nxt;
	}
}
int main()
{
	int n = r(),m = r(),k = r(),s = 1,t = n,x,y,z;
	while (m--) x = r(),y = r(),z = r(),add(x,y,z),add(y,x,z);
	memset(dis,0x7f,sizeof(dis));
	tot = 0;
	dis[s][0] = 0;
	push(s,0);
	while (tot)
	{
		int p,ed;
		pop(p,ed);
		for (int a = first[p],b = e[a].to ; a ; a = e[a].ne,b = e[a].to)
		{
			if (dis[p][ed] + e[a].v < dis[b][ed])
			{
				dis[b][ed] = dis[p][ed] + e[a].v;
				if (!o[b][ed]) push(b,ed);
			}
			if (ed == k) continue;
			if (dis[b][ed + 1] > dis[p][ed])
			{
				dis[b][ed + 1] = dis[p][ed];
				if (!o[b][ed + 1]) push(b,ed + 1);
			}
		}
	}
	printf("%d\n",dis[t][k]);
	return 0;
}

 

雙倍經驗 這題

三倍經驗 開通我校會員專屬