迪杰斯特拉+拆点 Deliver the Cake - HDU 6805
题意:
t组输入,给你n个点m条边。你需要输出从s点到t点的最短距离,然后是m条边,每条边输入信息为:
a,b,c 表示从a点到b点的一个无向边长度为c
每一个点会有一个属性L、R或M
如果a和b一个为L,另一个为R,那么a和b之间的距离要增加x,即变为x+c
其他情况权值还是c
题解:
我们可以注意到M类型的点是一个特殊点,无论是L类型还是R类型的点和它相连,它们的距离都不会增加x
那么我么可以把M类型的点拆成两个点,例如a点为M类型的点,那么我们可以把a点变为L类型的点,a+n点变为R类型的点
这个样子去构造一个图,然后如果起点s是一个M类型的点,我们就让起点s和s+n都和0号点连一条权值为0的无向边,然后以0为起点跑一边迪杰斯特拉
否则,就直接以s点为起点跑一边迪杰斯特拉
代码:
#include <stack> #include <queue> #include <map> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define fi first #define se second using namespace std; typedef long long ll; const int maxn=2e5+10; const int INF=0x3f3f3f3f; ll n,m,v[maxn]; char f[maxn]; struct shudui { ll start,val; bool operator < (const shudui y)const { return val>y.val; } } str1,str2; priority_queue<shudui>r; vector<shudui>w[maxn]; void JK(ll st) { memset(v,INF,sizeof(v)); v[st]=0; str1.start=st; str1.val=0; r.push(str1); while(!r.empty()) { ll x,y; str1=r.top(); r.pop(); x=str1.start; y=str1.val; if(v[x]<y) continue; //说明在这个点再此之后又入队了 //此次出队的并不是s到这个点的最短路, //所以在这次更新前点v所连的点已经更过一次了 //所以后面也不会进行松弛操作 ll len=w[x].size(); for(ll i=0;i<len;++i) { str2=w[x][i]; if((v[x]+str2.val<v[str2.start])) { v[str2.start]=v[x]+str2.val; str1.start=str2.start; str1.val=v[str2.start]; r.push(str1); } } } } void add_edge(ll a,ll b,ll c) { str2.start=b; str2.val=c; w[a].push_back(str2); str2.start=a; w[b].push_back(str2); } int main() { ll t; scanf("%lld",&t); while(t--) { ll s,t,x; scanf("%lld%lld%lld%lld%lld",&n,&m,&s,&t,&x); for(ll i=0;i<=2*n;++i) w[i].clear(); scanf("%s",f+1); while(m--) { ll a,b,c; scanf("%lld%lld%lld",&a,&b,&c); if(f[a]==f[b]&&(f[a]=='L'||f[b]=='R')) { add_edge(a,b,c); } else if(f[a]!=f[b]&&f[a]!='M'&&f[b]!='M') { add_edge(a,b,c+x); } else if(f[a]=='L'&&f[b]=='M') { add_edge(a,b,c); add_edge(a,b+n,c+x); } else if(f[a]=='M'&&f[b]=='L') { add_edge(a,b,c); add_edge(a+n,b,c+x); } else if(f[a]=='R'&&f[b]=='M') { add_edge(a,b,c+x); add_edge(a,b+n,c); } else if(f[a]=='M'&&f[b]=='R') { add_edge(a+n,b,c); add_edge(a,b,c+x); } else { add_edge(a,b,c); add_edge(a,b+n,c+x); add_edge(a+n,b,c+x); add_edge(a+n,b+n,c); } } ll ans=0; if(f[s]=='M') { add_edge(0,s,0); add_edge(0,s+n,0); JK(0); ans=min(v[t],v[t+n]); } else { JK(s); //printf("%lld %lld \n",v[t],v[t+n]); ans=min(v[t],v[t+n]); } printf("%lld\n",ans); } return 0; }