题意:momo想从s城市出发到t城市去,有两种交通工具可以选择,一个是公交车,一个是轻轨。并且momo认为换车是一个麻烦的事情,所以momo不会在一个城市换车后到下一个城市又换车,即momo两次换车之间最少中间经过了一个城市。
典型的最短路+状态压缩DP,设d[i][j],i表示第i个点,j用二进制表示上一个点所乘车辆和当前所乘车辆,即00,01,10,11分别用0~3表示状态,采用SPFA,只用开俩个队列,一个存当前压入点,另一个存当前压入点的状态,根据当前点的状态判断状态转移。。。
//spfa+dp
#include <iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=2010,maxm=20010;
const int inf=1000000000;
int s,e,cnt,n,m;
int head[maxn];
struct EDGE{
int v,w[2],next;
}edge[2*maxm];
void addedge(int u,int v,int w1,int w2){
edge[cnt].v=v; edge[cnt].w[0]=w1; edge[cnt].w[1]=w2;
edge[cnt].next=head[u]; head[u]=cnt++;
}
void spfa(){
int i,d[maxn][4],u,vis[maxn][4],t;
queue <int>q; queue<int>dp;
for(int i=1;i<=n;i++){
for(int j=0;j<4;j++){
d[i][j]=inf; vis[i][j]=0;
}
}
d[s][1]=d[s][2]=0;
vis[s][1]=vis[s][2]=1;
q.push(s); dp.push(1);
q.push(s); dp.push(2);
while(!q.empty())
{
int zt;
u=q.front(); q.pop();
t=dp.front(); dp.pop();
vis[u][t]=0;
if(t%3){
if(2-t)
zt=3;
else
zt=0;
for(i=head[u];i!=-1;i=edge[i].next)
if(d[u][t]+edge[i].w[2-t]<d[edge[i].v][zt]){
d[edge[i].v][zt]=d[u][t]+edge[i].w[2-t];
if(!vis[edge[i].v][zt]){
vis[edge[i].v][zt]=1;
q.push(edge[i].v); dp.push(zt);
}
}
}
else if(t==0){
for(int k=0;k<=1;k++)
for(i=head[u];i!=-1;i=edge[i].next)
if(d[u][t]+edge[i].w[k]<d[edge[i].v][k]){
d[edge[i].v][k]=d[u][t]+edge[i].w[k];
if(!vis[edge[i].v][k]){
vis[edge[i].v][k]=1;
q.push(edge[i].v); dp.push(k);
}
}
}
else{
for(int k=0;k<=1;k++)
for(i=head[u];i!=-1;i=edge[i].next)
if(d[u][t]+edge[i].w[k]<d[edge[i].v][2+k]){
d[edge[i].v][2+k]=d[u][t]+edge[i].w[k];
if(!vis[edge[i].v][2+k]){
vis[edge[i].v][2+k]=1;
q.push(edge[i].v); dp.push(2+k);
}
}
}
}
int minn=inf;
for(int i=0;i<4;i++)
minn=min(minn,d[e][i]);
printf("%d\n",minn);
}
int main()
{
//freopen("momo.txt","r",stdin);
int u,v,w1,w2;
while(~scanf("%d %d",&n,&m)){
memset(head,-1,sizeof(head));
cnt=0;
for(int i=0;i<m;i++){
scanf("%d%d%d%d",&u,&v,&w1,&w2);
addedge(u,v,w1,w2);
addedge(v,u,w1,w2);
}
scanf("%d%d",&s,&e);
spfa();
}
return 0;
}