n 个点,p 条边的无向图.
最多可将图中的 k 条路权值变为 0,并定义该图的权值为 1 到 n 的所有选择方案中最大权值路的最小值.
求该图权值,如果 1 到 n 不存在路径,输出 -1.
① SPFA + DP
设 dis[v][k] 为从 1 到 v 的路径中选择了 k 条路权值为 0 的最短距离.
每次有两种方案:
1. 将该边的权值置为 0,即 dis[v][k] == dis[u][k].
2. 不对这条边进行处理,即 dis[v][k] == max(dis[u][k], Edge[i].w).
那么这就是 SPFA 中更新距离的核心.
详见代码.
② 二分 + SPFA
设该图权值为 mid,即从 1 到 n 所经过路中权值大于 mid 的路权值都要置为 0,即置为 0 路的个数应该小于等于 k.
设路权值大于 mid 的路的权值为 1,否则为 0,所求即 dis[n] <= k.
详见代码.
③ 分层图 + SPFA
分层图学习
① SPFA + DP
#include
#include
using namespace std;
const int M = (int)1e3;
const int inf = 0x3f3f3f3f;
int n, p, k;
int cnt;
int head[M + 5];
struct node
{
int v, w, nx;
}Edge[M * 20 + 5];
bool vis[M + 5];
int dis[M + 5][M + 5];
void init()
{
cnt = 0;
for(int i = 1; i <= n; ++i)
{
vis[i] = 0;
head[i] = -1;
for(int j = 0; j <= k; ++j)
dis[i][j] = inf;
}
}
void add(int u, int v, int w)
{
Edge[cnt].v = v;
Edge[cnt].w = w;
Edge[cnt].nx = head[u];
head[u] = cnt++;
}
void spfa(int s)
{
queue q;
q.push(s);
vis[s] = 1, dis[s][0] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = Edge[i].nx)
{
int v = Edge[i].v;
if(dis[v][0] > max(dis[u][0], Edge[i].w))
{
dis[v][0] = max(dis[u][0], Edge[i].w);
if(!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
for(int j = 1; j <= k; ++j)
{
if(dis[v][j] > min(dis[u][j - 1], max(dis[u][j], Edge[i].w)))
{
dis[v][j] = min(dis[u][j - 1], max(dis[u][j], Edge[i].w));
if(!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
}
}
}
}
int main()
{
scanf("%d %d %d", &n, &p, &k);
init();
for(int i = 0, u, v, w; i < p; ++i)
{
scanf("%d %d %d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
spfa(1);
int ans = inf;
for(int i = 0; i <= k; ++i)
ans = min(ans, dis[n][k]);
if(ans == inf) ans = -1;
printf("%d\n", ans);
return 0;
}
② 二分 + SPFA
#include
#include
#include
//#include
using namespace std;
const int M = (int)1e3;
const int inf = 0x3f3f3f3f;
int n, p, k;
int cnt;
int head[M + 5];
struct node
{
int v, w, nx;
}Edge[M * 20 + 5];
int dis[M + 5];
bool vis[M + 5];
void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int w)
{
Edge[cnt].v = v;
Edge[cnt].w = w;
Edge[cnt].nx = head[u];
head[u] = cnt++;
}
struct cmp
{
bool operator()(int a, int b)
{
return dis[a] > dis[b];
}
};
priority_queue , cmp> q;
void spfa(int s, int mid)
{
memset(vis, 0, sizeof(vis));
memset(dis, inf, sizeof(dis));
q.push(s);
vis[s] = 1, dis[s] = 0;
while(!q.empty())
{
int u = q.top();
q.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = Edge[i].nx)
{
int v = Edge[i].v, w = (Edge[i].w > mid);
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if(!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
}
}
}
int main()
{
scanf("%d %d %d", &n, &p, &k);
init();
for(int i = 0, u, v, w; i < p; ++i)
{
scanf("%d %d %d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
int l = 0, r = inf, mid;
while(l < r)
{
mid = (l + r) >> 1;
spfa(1, mid);
if(dis[n] <= k)
r = mid;
else
l = mid + 1;
}
if(r == inf) r = -1;
printf("%d\n", r);
return 0;
}
③ 分层图 + SPFA
#include
#include
using namespace std;
const int M = (int)1e6;
const int inf = 0x3f3f3f3f;
int n, p, k;
int cnt;
int head[M + 5];
struct node
{
int v, w, nx;
}Edge[M * 5];
int dis[M + 5];
bool vis[M + 5];
void init()
{
cnt = 0;
for(int i = 1; i <= M; ++i)
{
vis[i] = 0;
head[i] = -1;
dis[i] = inf;
}
}
void add(int u, int v, int w)
{
Edge[cnt].v = v;
Edge[cnt].w = w;
Edge[cnt].nx = head[u];
head[u] = cnt++;
}
struct cmp
{
bool operator()(int a, int b)
{
return dis[a] > dis[b];
}
};
priority_queue , cmp> q;
void spfa(int s)
{
q.push(s);
vis[s] = 1, dis[s] = 0;
while(!q.empty())
{
int u = q.top();
q.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = Edge[i].nx)
{
int v = Edge[i].v;
if(dis[v] > max(dis[u], Edge[i].w))
{
dis[v] = max(dis[u], Edge[i].w);
if(!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
}
}
}
int main()
{
scanf("%d %d %d", &n, &p, &k);
init();
for(int i = 1, u, v, w; i <= p; ++i)
{
scanf("%d %d %d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
for(int j = 1; j <= k; ++j)
{
add(u + j * n, v + j * n, w);
add(v + j * n, u + j * n, w);
add(u + (j - 1) * n, v + j * n, 0);
add(v + (j - 1) * n, u + j * n, 0);
}
}
for(int i = 1; i <= k; ++i)
add(i * n, (i + 1) * n, 0);
spfa(1);
printf("%d\n", dis[(k + 1) * n] == inf ? -1 : dis[(k + 1) * n]);
return 0;
}