还是挺不错的
想到从终点反过来跑一次然后标记一下边 最后再正着跑一次最短路就好
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define me(a,x) memset(a,x,sizeof a)
#define cp(a,x) memcpy(a,x,sizeof a)
using namespace std;
typedef long long LL;
const int N=10010,inf=1e9;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
struct node{int y,c[2],d,next;}a[5*N],b[5*N]; int len,first[2][N];
void ins(int x,int y,int c0,int c1)
{
b[++len].y=y,b[len].next=first[0][x],first[0][x]=len,b[len].d=2;
a[len].y=x,a[len].c[0]=c0,a[len].c[1]=c1;
a[len].next=first[1][y],first[1][y]=len;
}
queue<int>q;
int n,m,d[2][N],l[2][N]; bool v[N];
void spfa(int o)
{
for(int i=1;i<=n;i++)d[o][i]=inf,v[i]=0;
d[o][n]=0,v[n]=1;
q.push(n);
while(!q.empty())
{
int x=q.front(); q.pop(); v[x]=0;
for(int k=first[1][x];k;k=a[k].next)
{
int y=a[k].y;
if(d[o][y]>d[o][x]+a[k].c[o])
{
d[o][y]=d[o][x]+a[k].c[o];
l[o][y]=k;
if(!v[y]){v[y]=1; q.push(y);}
}
}
}
}
int f[N];
int main()
{
int i,j,x,y,c0,c1;
n=read(),m=read();
for(i=1;i<=m;i++)
{
x=read(),y=read(),c0=read(),c1=read();
ins(x,y,c0,c1);
}
spfa(0),spfa(1);
for(i=1;i<=n;i++)
{
if(l[0][i]) b[l[0][i]].d--;
if(l[1][i]) b[l[1][i]].d--;
v[i]=0,f[i]=inf;
}
q.push(1); f[1]=0,v[1]=1;
while(!q.empty())
{
x=q.front(),v[x]=0,q.pop();
for(int k=first[0][x];k;k=b[k].next)
{
y=b[k].y;
if(f[y]>f[x]+b[k].d)
{
f[y]=f[x]+b[k].d;
if(!v[y]){v[y]=1; q.push(y);}
}
}
}
printf("%d\n",f[n]);
return 0;
}