题目链接
https://codeforces.com/contest/1473/problem/E
题意
给定一张带权无向无环图,求(1)号点到其他点的最小路径权值。
路径的权值等于路径上所有边的权值和加上路径上最小的边减去最大的边。
思路
分层图最短路,减去最大值就看成一条边免费,免费的边建一层,加上最小值就看成双倍贡献,双倍的边建一层, 然后还有只有一条边的情况单独一层(比赛没考虑这点,看出是分层图少了一层没做出来!)。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 50;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int n, m, k;
int head[maxn], vis[maxn];
int cnt;
ll dis[maxn];
struct edge{
int to, next;
ll w;
};
edge es[maxn << 2];
void init(int n)
{
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
fill(dis, dis + 4 * n + 1, INF);
cnt = 0;
}
void add(int u,int v,ll w)
{
es[cnt].to = v;
es[cnt].w = w;
es[cnt].next = head[u];
head[u] = cnt++;
}
void ins(int u, int v, ll w){
add(u ,v, w); add(v, u, w);
}
struct node
{
int pos;
ll cost;
node(int pos, ll cost):pos(pos),cost(cost){}
friend bool operator < (node a,node b){
return a.cost > b.cost;
}
};
void dijkstra(int st)
{
priority_queue<node> q;
dis[st] = 0;
q.push(node(st,0));
while(!q.empty())
{
node now = q.top();
q.pop();
int t = now.pos;
if(vis[t]) continue;
vis[t] = 1;
for(int i = head[t];i != -1;i = es[i].next)
{
int v = es[i].to;
if(dis[v] > dis[t] + es[i].w)
{
dis[v] = dis[t] + es[i].w;
q.push(node(v, dis[v]));
}
}
}
}
int main()
{
std::ios::sync_with_stdio(false);
cin >> n >> m;
init(n);
for(int i = 1;i <= m;i++){
int u, v;
ll w;
cin >> u >> v >> w;
for(int j = 0;j < 2;j++){
//每层的图
add(u, v, w);
add(u + n, v + n, w);
add(u + 2 * n, v + 2 * n, w);
add(u + 3 * n, v + 3 * n, w);
//选择max
add(u, v + n, 0);
add(u + 2 * n, v + 3 * n, 0);
//选择min
add(u, v + 2 * n, 2LL * w);
add(u + n, v + 3 * n, 2LL * w);
//选择 min, max
add(u, v + 3 * n, w);
swap(u, v);
}
}
dijkstra(1);
for(int i = 2;i <= n;i++){
ll ans = min(dis[i], dis[i + 3 * n]);
cout << ans << " ";
}
return 0;
}