4289: PA2012 Tax

版权声明:菜鸡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);
}

猜你喜欢

转载自blog.csdn.net/qq_36808030/article/details/85470905