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;
}

(完)

 

posted @ 2019-11-02 00:49  阿基米德的澡盆  阅读(193)  评论(0编辑  收藏  举报