[AHOI2017初中組]guide
阿新 • • 發佈:2018-10-16
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