题目:E. Minimum Path
分析:
这个题首先是最短路问题。
只保留公式的第一项的话,就是最朴素的最短路问题。
现在加了两项,很显然是最短路的变形。
现在我们可以定义最短路为:总路径长度必须删除一条边的权值、添加一条边的权值。
这样我们可以将原来的一维dis数组升为3维,dis[i][j][k],j表示是否删除了一条边,k表示是否添加了一条边。
dis[i][1][1]就是最终我们要求的
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//三年竞赛一场空,不开long long见祖宗
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
#define pb(a) push_back(a)
#define x first
#define y second
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
struct edge
{
int ep;
ll val;
int nex;
}e[maxn << 1];
int head[maxn], tot;
void init(){
mem(head, -1), tot = 0;
}
void addedge(int x, int y, ll val)
{
e[tot] = edge{y, val, head[x]};
head[x] = tot++;
}
struct node
{
int u;
ll dis;
int flag1, flag2;
bool operator< (const node& b) const
{
return b.dis < dis;
}
};
ll dis[maxn][2][2];
int vis[maxn][2][2];
void dj()
{
mem(dis, 0x3f);
mem(vis, 0);
priority_queue<node> q;
q.push(node{1, 0, 0, 0});
dis[1][0][0] = 0;
while(!q.empty())
{
node now = q.top(); q.pop();
int u = now.u, flag1 = now.flag1, flag2 = now.flag2;
ll nowdis = now.dis;
if(vis[u][flag1][flag2]) continue;
vis[u][flag1][flag2] = 1;
for(int i = head[u]; ~i; i = e[i].nex)
{
int ep = e[i].ep;
if(dis[ep][flag1][flag2] > nowdis + e[i].val)
dis[ep][flag1][flag2] = nowdis + e[i].val, q.push(node{ep, dis[ep][flag1][flag2], flag1, flag2});
if(!flag1 && dis[ep][1][flag2] > nowdis)
dis[ep][1][flag2] = nowdis, q.push(node{ep, dis[ep][1][flag2], 1, flag2});
if(!flag2 && dis[ep][flag1][1] > nowdis + 2 * e[i].val)
dis[ep][flag1][1] = nowdis + 2 * e[i].val, q.push(node{ep, dis[ep][flag1][1], flag1, 1});
if(!flag1 && !flag2 && dis[ep][1][1] > nowdis + e[i].val)
dis[ep][1][1] = nowdis + e[i].val, q.push(node{ep, dis[ep][1][1], 1, 1});
}
}
}
int main()
{
init();
int n, m; cin >> n >> m;
for(int i = 1; i <= m; i++)
{
int x, y;
ll val;
cin >> x >> y >> val;
addedge(x, y, val), addedge(y, x, val);
}
dj();
for(int i = 2; i <= n; i++)
printf("%lld%c", dis[i][1][1], i == n ? '\n' : ' ');
}