1. 程式人生 > >(好題)2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest F Pizza Delivery

(好題)2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest F Pizza Delivery

void nal bsp return 細節 就會 情況 ++ turn

題意:給n個點m條邊的有向圖。每次使一條邊反向,問你1到2的最短路變短,變長,還是不變。

解法:遇到這種題容易想到正向求一遍最短路d1,反向再求一遍最短路d2。紀錄原圖上的最短路為ans,然後分開考慮各種情況。

變短的情況:d1[y[i]]+d2[x[i]]+z[i]<ans

否則就剩下不變和變長兩種情況:那麽如果邊(x,y)是起點到終點的最短路必須邊的話,就會變長,否則會不變。

接下來的問題是 怎麽求最短路的必經邊?

求出原圖1到2最短路圖(這裏要和求單源點的最短路圖區別開來,單源點的最短路圖使起點到所有其他點的最短路的集合),求法:如果d1[x[i]]+z[i]+d2[y[i]]==ans的話邊(x[i],y[i])就在起點到終點的最短路圖上。 把這個圖變為無向圖,用tarjan求橋。如果邊(x,y)是橋的話就是必經邊,否則為非必經邊。

細節詳見代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pii;
const int N=1e5+10;
LL n,m,ans;
LL d1[N],d2[N],x[N],y[N],z[N];

LL cnt=1,head[N],to[N<<1],nxt[N<<1],len[N<<1];
void add_edge(LL x,LL y,LL z) {
    nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt;
}

bool vis[N]; priority_queue<pii> q; void Dijkstra(LL d[],LL s) { while (!q.empty()) q.pop(); memset(vis,0,sizeof(vis)); d[s]=0; q.push(make_pair(0,s)); while (!q.empty()) { pii x=q.top(); q.pop(); if (vis[x.second]) continue; vis[x.second]=1;
for (LL i=head[x.second];i;i=nxt[i]) { LL y=to[i]; if (d[y]>d[x.second]+len[i]) { d[y]=d[x.second]+len[i]; q.push(make_pair(-d[y],y)); } } } } int num,low[N],dfn[N],bridge[N]; void tarjan(int x,int in) { dfn[x]=low[x]=++num; for (int i=head[x];i;i=nxt[i]) { int y=to[i]; if (!dfn[y]) { tarjan(y,i); low[x]=min(low[x],low[y]); if (low[y]>dfn[x]) bridge[len[i]]=bridge[len[i^1]]=1; } else if (i!=(in^1)) low[x]=min(low[x],dfn[y]); } } void getbridge() { cnt=1; memset(head,0,sizeof(head)); for (int i=1;i<=m;i++) if (d1[x[i]]+z[i]+d2[y[i]]==ans) add_edge(x[i],y[i],i),add_edge(y[i],x[i],i); for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i,0); } int main() { cin>>n>>m; for (int i=1;i<=m;i++) scanf("%lld%lld%lld",&x[i],&y[i],&z[i]); memset(d1,0x3f,sizeof(d1)); memset(d2,0x3f,sizeof(d2)); for (int i=1;i<=m;i++) add_edge(x[i],y[i],z[i]); Dijkstra(d1,1); cnt=1; memset(head,0,sizeof(head)); for (int i=1;i<=m;i++) add_edge(y[i],x[i],z[i]); Dijkstra(d2,2); ans=d1[2]; getbridge(); for (int i=1;i<=m;i++) if (ans>d1[y[i]]+d2[x[i]]+z[i]) puts("HAPPY"); else if (bridge[i]) puts("SAD"); else puts("SOSO"); return 0; }

(好題)2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest F Pizza Delivery