分層圖
作用
分層圖可以處理從圖中選取k條邊使其邊權變爲0,求最短路
一個很好的例子
Illegal Motor
(Motor.c/cpp/pas)
Description
在你的強力援助下,PCY 成功完成了之前的所有任務,他覺得,現在正是出去浪的大好時光。於是,他來到高速公路上,找到一輛摩的前往幾千公里以外他心儀的那家黃燜雞米飯。
由於 PCY 的品味異於常人,途經幾百個城市的黃燜雞米飯他都不屑一顧,他只願意前往他心中最好的那家,但是爲了一碗二十塊錢的黃燜雞米飯,他不願意花上幾千塊的路費,他希望路費盡量少。高速路上的警察叔叔被他的行爲所打動,於是在多方協調下,最多 K 條城市之間的高速收費站願意免費爲 PCY 放行(可以任意選擇)。
顯然,PCY 已經筋疲力盡,不想再動用自己的數學天才來計算他可以花費的最小路費,因此他希望你可以幫他最後一次,他說他可以請你吃大碗的黃燜雞米飯,還可以加一瓶豆奶。
現在給你 N 個城市(編號爲 0 … N - 1 ), M 條道路,和每條高速公路的花費 Wi ,以及題目所描述的 K。PCY 想從城市 S 到城市 T, 因爲他對 T 城市的黃燜雞米飯情有獨鍾。
Input (Prefix.in)
第一行,三個整數 N,M,K ,如題意所描述
第二行,兩個整數 S,T ,代表出發城市和目標城市編號
接下來 M 行,每行三個整數 X,Y,W ,代表 X 和 Y 城市之間的高速公路收費爲 W 元
Output (Prefix.out)
共一行,輸出一個整數,代表 PCY 最少需要花費的路費。
1.in
5 6 1
1 5
3 4 5
1 2 15
2 3 5
4 5 5
3 4 3
1 3 1005
1.out
8
2.in
4 3 1
1 4
1 2 50
2 3 30
1 4 50
2.out
0
Hint
對於 10%的數據, N <= 100,K = 0
對於 30%的數據, N <= 5,M <= 10,K <= 2
對於 100%的數據, N <= 10,M <= 50,K <= 10,Wi <= 10
內存限制 256M ,時間限制 1s
思路
借鑑Kigo的想法,分層圖就是K層平行宇宙,每一層裏有一個完整的圖,但平行宇宙之間有互相連通的蟲洞,可以從一個平行宇宙中的一個點瞬間到達下一個平行宇宙(原先x->y 邊權爲w,現在x->y’邊權爲0),然而蟲洞是單向的,你不能回到上一個平行宇宙,只能向下一個平行宇宙走;最終,每一個平行宇宙都有同樣的目的地,看到哪一個目的地最省錢
在這裏,K層分層圖說明最多有K條0邊權的路可以走,建圖後跑最短路即可
SPFA(本題不好)
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXM 5000000
using namespace std;
int s,t,n,m,k;
inline int Read(){
int x=0;char ch=getchar();
while(ch<'0' || ch>'9'){ch=getchar();}
while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
struct E{
int next,to,v;
}edge[MAXM];
int head[MAXM];int edge_num;
int dis[MAXM];
void addedge(int x,int y,int z){
edge[++edge_num].next=head[x];
edge[edge_num].to=y;
edge[edge_num].v=z;
head[x]=edge_num;
}
int que[MAXM];int front,tail;
bool inque[MAXM];
void PUSH(int x){
tail++;
if(tail==5000000) tail=1;
que[tail]=x;inque[x]=1;
}
int POP(){
front++;
if(front==5000000) front=1;
int t=que[front];
inque[t]=0;
return t;
}
void SPFA(int x){
memset(dis,0x7f,sizeof(dis));
PUSH(x);
dis[x]=0;
while(front<tail){
int fro=POP();
int i;
for(i=head[fro];i;i=edge[i].next){
if(dis[edge[i].to]>dis[fro]+edge[i].v){
dis[edge[i].to]=dis[fro]+edge[i].v;
if(!inque[edge[i].to]){
PUSH(edge[i].to);
}
}
}
}
}
void solve(){
SPFA(s);
int i;
int ans=0x7fffffff;
for(i=0;i<=k;i++){
ans=min(ans,dis[t+n*i]);
}
printf("%d\n",ans);
}
int main(){
freopen("Motor.in","r",stdin);
freopen("Motor.out","w",stdout);
n=Read();m=Read();k=Read();s=Read();t=Read();
int i;
if(k==0){
for(i=1;i<=m;i++){
int a=Read();int b=Read();int c=Read();
int j;
addedge(a,b,c);
addedge(b,a,c);
}
SPFA(s);
printf("%d\n",dis[t]);
return 0;
}
for(i=1;i<=m;i++){
int a=Read();int b=Read();int c=Read();
int j;
for(j=0;j<=k;j++){
addedge(a+n*j,b+n*j,c);
addedge(b+n*j,a+n*j,c);
if(j<k){
addedge(a+n*j,b+n*(j+1),0);
addedge(b+n*j,a+n*(j+1),0);
}
}
}
solve();
return 0;
}
堆優化Dijsktra(好)(STD)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 200005;
const int maxm = 4000005;
const int inf = 0x3f3f3f3f;
void Read(int& x)
{
char t = getchar();
while (t < '0' || t > '9') t = getchar();
x = 0;
while (t >= '0' && t <= '9') {
x = x * 10 + t - '0';
t = getchar();
}
}
struct Heap
{
int place[maxn], val[maxn], idx[maxn], node_cn;
Heap() { node_cn = 0; memset(place, 0, sizeof(place)); }
inline void Swap(int x, int y)
{
swap(place[idx[x]], place[idx[y]]);
swap(val[x], val[y]);
swap(idx[x], idx[y]);
}
void adjustup(int x)
{
while (x > 1) {
if (val[x] < val[x >> 1]) {
Swap(x, x >> 1);
x >>= 1;
} else {
break;
}
}
}
void adjustdown(int x)
{
int v;
while ((x << 1) <= node_cn) {
v = x << 1;
if (v + 1 <= node_cn && val[v + 1] < val[v]) v = v + 1;
if (val[x] > val[v]) {
Swap(x, v);
x = v;
} else {
break;
}
}
}
void insert(int id, int v)
{
if (place[id]) {
val[place[id]] = -inf;
adjustup(place[id]);
val[1] = v;
adjustdown(1);
} else {
node_cn ++;
val[node_cn] = v, idx[node_cn] = id, place[id] = node_cn;
adjustup(node_cn);
}
}
void pop()
{
Swap(1, node_cn);
node_cn --;
adjustdown(1);
}
};
int fst[maxn], edge_cn = 0;
int u[maxm], v[maxm], w[maxm], nxt[maxm];
void addedge(int x, int y, int _w)
{
edge_cn ++;
u[edge_cn] = x, v[edge_cn] = y, w[edge_cn] = _w;
nxt[edge_cn] = fst[x];
fst[x] = edge_cn;
}
int n, m, k, s, t;
int dis[maxn];
void input()
{
int x, y, z;
memset(fst, -1, sizeof(fst));
Read(n), Read(m), Read(k);
Read(s), Read(t);
for (register int i = 1; i <= m; i++) {
Read(x), Read(y), Read(z);
for (register int j = 0; j <= k; j++) {
addedge(x + n * j, y + n * j, z);
addedge(y + n * j, x + n * j, z);
if (j < k) {
addedge(x + n * j, y + n * (j + 1), 0);
addedge(y + n * j, x + n * (j + 1), 0);
}
}
}
}
Heap heap;
bool vis[maxn];
void Dijsktra()
{
int cn;
memset(dis, inf, sizeof(dis));
dis[s] = 0;
heap.insert(s, 0);
while (heap.node_cn) {
cn = heap.idx[1];
heap.pop();
if (vis[cn]) continue;
vis[cn] = true;
for (register int i = fst[cn]; i != -1; i = nxt[i]) {
if (!vis[v[i]] && dis[v[i]] > dis[cn] + w[i]) {
dis[v[i]] = dis[cn] + w[i];
heap.insert(v[i], dis[v[i]]);
}
}
}
}
void solve()
{
int ans = inf;
Dijsktra();
for (register int i = 0; i <= k; i++) ans = min(ans, dis[t + i * n]);
printf("%d\n", ans);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("Motor.in", "r", stdin);
freopen("Motor.out", "w", stdout);
#endif
input();
solve();
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}