P3106 [USACO14OPEN]GPS的决斗(最短路)
化简:够简的了.....但是!翻译绝对有锅。
这个最短路是从n到每个点的单源最短路,也就是最短路径树。
那么,思路就很明确了。建两个图,然后跑两边SPFA,记录下最短路径。
然后,对于两点之间的边,如果最短路不经过它,那么最终图边权+1;
然后在最终图上(边权为0,1,2)跑一遍SPFA即可。
一开始我想复杂了,在想怎么记录路径,怎么重构图.balabala。
然后发现,怎么才能让两点不在最短路径上呢?
SPFA的松弛操作,依据是三角不等式。于是,如果两点之间的最短路的距离如果不等于边权(也就是最短路径不过它俩之间的边)那么就它就是一条会报警的边。
$$看来SPFA最重要的是三角不等式$$
于是,只要暴力跑三遍SPFA即可。
用尽浑身解数,信仰SPFA,各种常数优化,读入挂,我还是没能跑到最优解的第一面....在第二页前几个徘徊.....
代码:(这么长的图论题也不多见,但是好像逛公园就那么长)
#include<iostream> #include<cstdio> #include<queue> #define rg register using namespace std; const int maxn=1e6+10; int n,m; inline int read() { int x=0,f=1;char s=getchar(); while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();} while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();} return x*f; } struct edge { int to,next,dis; }e1[maxn],e2[maxn],e[maxn]; int head[maxn],head1[maxn],head2[maxn]; int cnt1,cnt2,cnt; inline void addedge1(int from,int to,int dis) { e1[++cnt1].next=head1[from]; e1[cnt1].to=to; e1[cnt1].dis=dis; head1[from]=cnt1; } inline void addedge2(int from,int to,int dis) { e2[++cnt2].next=head2[from]; e2[cnt2].to=to; e2[cnt2].dis=dis; head2[from]=cnt2; } inline void addedge(int from,int to,int dis) { e[++cnt].next=head[from]; e[cnt].to=to; e[cnt].dis=dis; head[from]=cnt; } int dis1[maxn],vis1[maxn],pre1[maxn]; struct cmp1 { bool operator () (int a,int b) { return dis1[a]>dis1[b]; } }; inline void spfa1() { priority_queue < int , vector < int > , cmp1 > q; for(rg int i=1;i<=n;i++) { dis1[i]=2147483647; vis1[i]=0; } q.push(n); dis1[n]=0; vis1[n]=1; while(!q.empty()) { int u=q.top(); q.pop(); vis1[u]=0; for(rg int i=head1[u];i;i=e1[i].next) { int v=e1[i].to; if(dis1[v]>dis1[u]+e1[i].dis) { dis1[v]=dis1[u]+e1[i].dis; if(vis1[v]==0) { vis1[v]=1; q.push(v); } } } } } int dis2[maxn],vis2[maxn],pre2[maxn]; struct cmp2 { bool operator () (int a,int b) { return dis2[a]>dis2[b]; } }; inline void spfa2() { priority_queue < int , vector < int > , cmp2 > q; for(rg int i=1;i<=n;i++) { dis2[i]=2147483647; vis2[i]=0; } q.push(n); dis2[n]=0; vis2[n]=1; while(!q.empty()) { int u=q.top(); q.pop(); vis2[u]=0; for(rg int i=head2[u];i;i=e2[i].next) { int v=e2[i].to; if(dis2[v]>dis2[u]+e2[i].dis) { dis2[v]=dis2[u]+e2[i].dis; if(vis2[v]==0) { vis2[v]=1; q.push(v); } } } } } int dis[maxn],vis[maxn]; struct cmp { bool operator () (int a,int b) { return dis[a]>dis[b]; } }; inline void rebuild() { for(rg int i=1;i<=n;i++) { for(int j=head1[i];j;j=e1[j].next) { int v1=e1[j].to; int v2=e2[j].to; //cout<<i<<' '<<v1<<endl; int d=0; if(dis1[v1]-dis1[i]!=e1[j].dis) d++; if(dis2[v2]-dis2[i]!=e2[j].dis) d++; addedge(v1,i,d); } } } inline void spfa() { priority_queue < int , vector < int > , cmp > q; for(rg int i=1;i<=n;i++) { dis[i]=2147483647; vis[i]=0; } q.push(1); dis[1]=0; vis[1]=1; while(!q.empty()) { int u=q.top(); q.pop(); vis[u]=0; for(rg int i=head[u];i;i=e[i].next) { int v=e[i].to; if(dis[v]>dis[u]+e[i].dis) { dis[v]=dis[u]+e[i].dis; if(vis[v]==0) { vis[v]=1; q.push(v); } } } } } int main() { n=read(); m=read(); for(rg int i=1;i<=m;i++) { int a=read(),b=read(),c=read(),d=read(); //scanf("%d%d%d%d",&a,&b,&c,&d); addedge1(b,a,c); addedge2(b,a,d); //addedge(a,b,0); } spfa1(); spfa2(); rebuild(); spfa(); printf("%d",dis[n]); return 0; }
(完)