【Gym - 101986F】Pizza Delivery(Dijkstra最短路,建图方式,反向建图,Tarjan求桥,图论模板)
生活随笔
收集整理的這篇文章主要介紹了
【Gym - 101986F】Pizza Delivery(Dijkstra最短路,建图方式,反向建图,Tarjan求桥,图论模板)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題干:
題目大意:
一個有向圖,編號1~n的n個點,m條邊,規定1為起點,2為終點,問對于每一條邊,反轉它的方向,最短路會不會發生改變,如果變短了,輸出HAPPY,變長了或者到達不了了輸出SAD,不變的話輸出SOSO。
解題報告:
建三個圖,正向圖G1,反向圖G2,對于G1的邊(u,v),假如G1.d[u]+G2.[v]+w==G1.d[2],那么他就是最短路上的一條路徑,用這些路徑重新建一個圖G3,那么顯然這個G3中任意一條點1到點2的路徑都是最短路,對G3跑一遍tarjan求個橋,標記處理一下對應G1的哪條邊,記下編號。然后枚舉G1的每一條邊,如果G1.d[v]+G2.[u]+w==G1.d[2],那么就是HAPPY,否則分兩種情況:如果這條邊是橋,那么改變它的方向是會改變新圖的連通性的,必定不能到達2點,輸出SAD;如果不是橋,那么就是SOSO,因為有別的方式可以到達點2。
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e5 + 5; struct Edge {int fr,to;ll w;int ne; // Edge(int fr=0,int to=0,ll w=0,int ne=-1):fr(fr) }; struct Graph {struct Point {int pos;ll c;Point(){}Point(int pos,ll c):pos(pos),c(c){}bool operator<(const Point b) const {return c > b.c;}};Edge e[MAX];int tot = 0;//總共tot條邊,編號0~(tot-1) int head[MAX],id[MAX];bool vis[MAX];ll d[MAX];void add(int u,int v,ll w) {e[tot].fr = u;e[tot].to = v;e[tot].ne = head[u];e[tot].w = w;head[u] = tot++; }void Dijkstra(int st) {priority_queue<Point> pq;memset(d,0x3f,sizeof d);memset(vis,0,sizeof vis);d[st] = 0;pq.push(Point(st,0));while(pq.size()) {Point cur = pq.top();pq.pop();if(vis[cur.pos]) continue;vis[cur.pos] = 1; for(int i = head[cur.pos]; ~i; i = e[i].ne) {if(d[e[i].to] > d[cur.pos] + e[i].w) {d[e[i].to] = d[cur.pos] + e[i].w;pq.push(Point(e[i].to,d[e[i].to]));}}}}///int clk = 0;int DFN[MAX],LOW[MAX],bi[MAX];void id_add(int u,int v,ll w,int _id) {e[tot].fr = u;e[tot].to = v;e[tot].ne = head[u];e[tot].w = w;id[tot] = _id;//記錄編號為tot的這條邊是第幾個點的 head[u] = tot++; }void tarjan(int x,int rt) {DFN[x] = LOW[x] = ++clk;for(int i = head[x]; ~i; i = e[i].ne) {if(e[i].to == rt) continue; if(!DFN[e[i].to]) {tarjan(e[i].to,x);LOW[x] = min(LOW[x],LOW[e[i].to]);if(LOW[e[i].to] > DFN[x]) { // printf("%d**%d\n",e[i].fr,e[i].to);bi[id[i]] = 1;}}else LOW[x] = min(LOW[x],DFN[e[i].to]); //或者不用判重邊了直接用這一句 // else if(e[i].to != rt)LOW[x] = min(LOW[x],DFN[e[i].to]); //而且其實不應該是直接用這一句 而應該是傳參的時候傳入邊的編號rt,這樣我們else if(i != (rt^1))這樣才對,因為這代表的才是,不是祖先邊的回邊。所以這里嚴格來說不能直接判斷是否是祖先節點,因為還有可能有重邊或者自環的情況,但是這題因為數據保證了所以無所謂。 }}void init() {tot = 0;clk = 0;memset(head,-1,sizeof head);} } G1,G2,G3; int main() {int n,m;int u,v;ll w;cin>>n>>m;G1.init();G2.init();G3.init();//G1是原圖,G2是反圖,G3是最短路無向子圖 for(int i = 1; i<=m; i++) {scanf("%d%d%lld",&u,&v,&w);G1.add(u,v,w);G2.add(v,u,w);//加反邊 }G1.Dijkstra(1);G2.Dijkstra(2);ll DIS = G1.d[2]; //構造G3這個最短路子圖。 for(int i = 0; i<G1.tot; i++) {u = G1.e[i].fr;v = G1.e[i].to;w = G1.e[i].w;if(G1.d[u] + G2.d[v] + w == DIS) { // printf("%d@@@@@@%d\n",u,v);G3.id_add(u,v,w,i);G3.id_add(v,u,w,i);}}G3.tarjan(1,-1);//改成0也可以過。for(int i = 0; i<G1.tot; i++) {u = G1.e[i].fr;v = G1.e[i].to;w = G1.e[i].w;if(G1.d[v] + G2.d[u] + w < DIS) puts("HAPPY");else if(G3.bi[i]) puts("SAD");else puts("SOSO");} return 0 ; }?
總結
以上是生活随笔為你收集整理的【Gym - 101986F】Pizza Delivery(Dijkstra最短路,建图方式,反向建图,Tarjan求桥,图论模板)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【HRBUST - 1621】迷宫问题I
- 下一篇: 第四大通信运营商登场!中国广电5G网络服