1. 程式人生 > >[AHOI2017初中組]guide

[AHOI2017初中組]guide

include can gps sca 賦值 head () emp 反向

[AHOI2017初中組]guide

最短路

題意

對於一張有向圖,每條邊有兩個邊權,有兩套GPS會分別按兩個邊權計算所在到終點的最短路,如果你不按其中一套GPS說的路走,就會產生1的抱怨,求從起點到終點的最少抱怨數

題解

因為每次兩套GPS都會判斷當前要去的點是否在當前點到終點的最短路上,所以我們可以反向建邊,跑出每套GPS從終點到每個點的最短路,然後我們重新建圖,依次枚舉原圖的每條邊,將邊權賦值為2,如果要去的點在某套GPS的最短路上,邊權減一.最後跑一遍最短路就可以得出\(ans\)

  • 反向建邊
  • 反向SPFA
  • 邊重構
  • 反向SPFA
  • \(ans\)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1e5+10;
int n,m,head[maxn],num;
int dis[maxn],dis1[maxn],di[maxn];
bool use[maxn];
struct fy{int from,to,d,dd,e,next;}q[maxn*5];
void add(int a,int b,int c,int d)
{
    q[++num]=(fy){a,b,c,d,0,head[a]};head[a]=num;
}
void sp()
{
    memset(dis,0x3f,sizeof dis);dis[n]=0;
    memset(dis1,0x3f,sizeof dis1);dis1[n]=0;
    queue<int>qq;qq.push(n);use[n]=true;
    while(!qq.empty())
    {
        int a=qq.front();qq.pop();use[a]=false;
        for(int i=head[a];i;i=q[i].next)
        {
            int b=q[i].to;
            if(dis[b]>dis[a]+q[i].d)
            {
                dis[b]=dis[a]+q[i].d;
                if(!use[b]){use[b]=true;qq.push(b);}
            }
        }
    }
    qq.push(n);use[n]=true;
    while(!qq.empty())
    {
        int a=qq.front();qq.pop();use[a]=false;
        for(int i=head[a];i;i=q[i].next)
        {
            int b=q[i].to;
            if(dis1[b]>dis1[a]+q[i].dd)
            {
                dis1[b]=dis1[a]+q[i].dd;
                if(!use[b]){use[b]=true;qq.push(b);}
            }
        }
    }
}
void sp1()
{
    memset(di,0x3f,sizeof di);di[n]=0;
    queue<int>qq;qq.push(n);use[n]=true;
    while(!qq.empty())
    {
        int a=qq.front();qq.pop();use[a]=false;
        for(int i=head[a];i;i=q[i].next)
        {
            int b=q[i].to;
            if(di[b]>di[a]+q[i].e)
            {
                di[b]=di[a]+q[i].e;
                if(!use[b]){use[b]=true;qq.push(b);}
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);int a,b,c,d;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&a,&b,&c,&d);
        add(b,a,c,d);
    }
    sp();//反向SPFA
    for(int i=1;i<=num;i++)//邊重構
    {
        d=2;a=q[i].from;b=q[i].to;
        if(dis[b]==dis[a]+q[i].d)d--;
        if(dis1[b]==dis1[a]+q[i].dd)d--;
        q[i].e=d;
    }
    sp1();
    printf("%d\n",di[1]);
    return 0;
}

[AHOI2017初中組]guide