题意:
给定n个点m条边的带权无向图,
对于一条路径,距离定义为 s u m ( w ) − m a x ( w ) + m i n ( w ) sum(w)-max(w)+min(w) sum(w)−max(w)+min(w),其中w是路径的边权集。
求点1到其他每个点的最短路。
数据范围:n,m<=2e5
解法:
-max(w)可以看作是可以免费走一条边,
+min(w)可以看作是必须额外走一条边.
令dp[i][j][k]表示点1到达点i,是否免费一条边,是否额外一条边的最小代价.
利用最短路算法进行dp的转移即可,显然最短路算法会智能的选择免费走max(w),额外走min(w)
最后d[i][1][1]就是答案.
code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define PI pair<int,int>
const int maxm=2e5+5;
struct Node{
int dist,i,j,k;
friend bool operator<(const Node& a,const Node& b){
return a.dist>b.dist;
}
};
vector<PI>g[maxm];
int mark[maxm][2][2];
int d[maxm][2][2];
int n,m;
void dj(){
for(int i=1;i<=n;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
d[i][j][k]=1e18;
}
}
}
d[1][0][0]=0;
priority_queue<Node>q;
q.push({
d[1][0][0],1,0,0});
while(q.size()){
int i=q.top().i;
int j=q.top().j;
int k=q.top().k;
q.pop();
if(mark[i][j][k])continue;
mark[i][j][k]=1;
for(auto p:g[i]){
int nt=p.first,w=p.second;
if(!mark[nt][j][k]&&d[nt][j][k]>d[i][j][k]+w){
//正常走
d[nt][j][k]=d[i][j][k]+w;
q.push({
d[nt][j][k],nt,j,k});
}
if(j==0){
//免去这条边的花费
if(!mark[nt][1][k]&&d[nt][1][k]>d[i][j][k]){
d[nt][1][k]=d[i][j][k];
q.push({
d[nt][1][k],nt,1,k});
}
}
if(k==0){
//额外加上这条边的花费
if(!mark[nt][j][1]&&d[nt][j][1]>d[i][j][k]+w+w){
d[nt][j][1]=d[i][j][k]+w+w;
q.push({
d[nt][j][1],nt,j,1});
}
}
if(j==0&&k==0){
//免去这条边的花费,同时额外加上这条边的花费
if(!mark[nt][1][1]&&d[nt][1][1]>d[i][j][k]+w){
d[nt][1][1]=d[i][j][k]+w;
q.push({
d[nt][1][1],nt,1,1});
}
}
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b,c;cin>>a>>b>>c;
g[a].push_back({
b,c});
g[b].push_back({
a,c});
}
dj();
for(int i=2;i<=n;i++){
cout<<d[i][1][1]<<' ';
}
return 0;
}