版权声明:菜鸡blog,随便转载 https://blog.csdn.net/qq_36808030/article/details/85470905
题意:
给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权。
题解:
拆点,每个点对应相应边权(这个权值只能连向它),差分(大的向小的边权为0),然后跑dij。
code:
#include<map>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define mp make_pair
using namespace std;
const LL inf=1LL<<60;
struct Node{
int x,y,c,next;
}a[4000010],e[200010];int len=0,last[400010];
int la[400010];
int st,cnt=0;
map<pair<int,int>,int> s;
LL dis[400010],ans=inf;
int n,m;
bool vis[400010],ch[400010];
void ins(int x,int y,int c)
{
a[++len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
}
struct node{
int x;LL d;
node() {}
node(int a,LL b) {x=a;d=b;}
};
bool operator < (node a,node b) {return a.d>b.d;}
priority_queue<node> q;
void dij()
{
memset(vis,false,sizeof(vis));
for(int i=0;i<=cnt;i++) dis[i]=inf;
dis[st]=0;q.push(node(st,0));
while(!q.empty())
{
node t=q.top();q.pop();
int x=t.x;if(ch[x]) ans=min(ans,dis[x]);
if(vis[x]) continue;
vis[x]=true;
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(dis[y]>dis[x]+a[i].c)
{
dis[y]=dis[x]+a[i].c;
q.push(node(y,dis[y]));
}
}
}
}
bool cmp(Node a,Node b) {return a.c<b.c;}
void add(int x,int c)
{
if(la[x]==c&&x!=1) return;
cnt++;
if(x==n) ch[cnt]=true;
if(s[mp(x,la[x])])
{
ins(s[mp(x,la[x])],cnt,c-la[x]);
ins(cnt,s[mp(x,la[x])],0);
}
s[mp(x,c)]=cnt;
la[x]=c;
}
void bt(int x,int y,int c)
{
int X=s[mp(x,c)],Y=s[mp(y,c)];
ins(X,Y,c);ins(Y,X,c);
}
int main()
{
scanf("%d %d",&n,&m);
memset(ch,false,sizeof(ch));
for(int i=1;i<=m;i++) scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].c);
e[++m].x=st;e[m].y=1;e[m].c=0;
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++) add(e[i].x,e[i].c),add(e[i].y,e[i].c),bt(e[i].x,e[i].y,e[i].c);
dij();
printf("%lld",ans);
}