日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Gym - 101986F Pizza Delivery(最短路+DAG必经边)

發布時間:2024/4/11 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Gym - 101986F Pizza Delivery(最短路+DAG必经边) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出一個n個點m條邊的有向無環圖,每條邊的權重為w,起點為1,終點為2,現在對每一條邊詢問:

若將該邊的方向取反,權值不變,則對最短路有無影響,分為三種情況討論:

  • 若最短路變短,輸出HAPPY
  • 若最短路不變,輸出SOSO
  • 若最短路變短,輸出SAD
  • 題目分析:我們可以用迪杰斯特拉,用正向邊跑一下起點的最短路,再用反向邊跑一下終點的最短路,然后在枚舉每條邊即可,我們假設d[st][i]是起點到點i的最短路,d[ed][i]是點i到終點的最短路,w為每條邊的權值

    當d[st][v]+d[ed][u]+w<d[st][ed]時,直接輸出HAPPY即可

    但是判斷SOSO和SAD就有點麻煩了,因為最短路不止有一條,我們分兩種情況討論:

  • 若當前邊不位于最短路上,則對答案無影響,輸出SOSO
  • 若當前邊位于最短路上
  • 若當前邊是最短路的必經邊,則最短路肯定變大,輸出SAD
  • 若當前邊不是最短路的必經邊,則對答案無影響,輸出SOSO
  • 這里就涉及到了該如何求最短路的必經邊呢?網上說可以用支配樹來做,也可以用dp來做,我不會支配樹,就說一下怎么用dp做吧

    因為是有向邊,所以我們可以拓撲排序一下,利用樹形dp的思想,每次給接下來的節點累加上當前的答案,從起點跑一邊,再從終點跑一邊,設dp[st][i]是從起點到點i的路線數,dp[ed][i]是從點i到終點的路線數,那么若當前邊/點為必經邊/點,需要滿足:

  • 邊:dp[st][u]*dp[ed][v]==dp[st][ed]
  • 點:dp[st][x]*dp[ed][x]==dp[st][ed]
  • 有了這個前置知識后,我們就可以輕松解決這個題目了,不過實現起來會很惡心人,注意一下要靜下心來慢慢寫,不然一處小細節可能就得調上一下午

    代碼:

    #include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;int n,m;struct Node {LL w;int to,from;Node(int FROM,int TO,LL W){from=FROM;w=W;to=TO;}Node(){}bool operator<(const Node& a)const{return w>a.w;} }edge[N];vector<Node>node[3][N];//鄰接表 vector<int>v[3][N];//拓撲排序 LL d[3][N];//最短路 ull dp[3][N];//到達該點有多少條路徑 int in[3][N];//入度 void Dijkstra(int x) {d[x][x]=0;priority_queue<Node>q;q.push(Node(0,x,0));while(!q.empty()){Node cur=q.top();q.pop();if(cur.w!=d[x][cur.to])continue;for(int i=0;i<node[x][cur.to].size();i++){int u=cur.to;int v=node[x][u][i].to;LL w=node[x][u][i].w;if(d[x][v]>d[x][u]+w){d[x][v]=d[x][u]+w;q.push(Node(0,v,d[x][v]));}}} }void topo(int x) {queue<int>q;for(int i=1;i<=n;i++) if(in[x][i]==0){q.push(i);dp[x][i]=1;}while(!q.empty()){int cur=q.front();q.pop();for(int i=0;i<v[x][cur].size();i++){int to=v[x][cur][i];dp[x][to]+=dp[x][cur];if(--in[x][to]==0)q.push(to);}} }int main() { // freopen("input.txt","r",stdin);while(scanf("%d%d",&n,&m)!=EOF){memset(d,inf,sizeof(d));memset(dp,0,sizeof(dp));memset(in,0,sizeof(in));for(int j=1;j<=2;j++)for(int i=1;i<=n;i++){node[j][i].clear();v[j][i].clear();}for(int i=1;i<=m;i++){int u,v,w;scanf("%d%d%d",&u,&v,&w);edge[i].from=u;edge[i].to=v;edge[i].w=w;node[1][u].push_back(Node(u,v,w));node[2][v].push_back(Node(v,u,w));}int st=1;int ed=2;Dijkstra(st);Dijkstra(ed);for(int i=1;i<=n;i++)for(int j=0;j<node[st][i].size();j++){int from=i;int to=node[st][i][j].to;LL w=node[st][i][j].w;if(d[st][from]+d[ed][to]+w==d[st][ed]){v[st][from].push_back(to);in[st][to]++;v[ed][to].push_back(from);in[ed][from]++;}}topo(st);topo(ed);for(int i=1;i<=m;i++){int u=edge[i].from;int v=edge[i].to;LL w=edge[i].w;if(d[st][v]+d[ed][u]+w<d[st][ed])printf("HAPPY\n");else if(d[st][v]+d[ed][u]+w==d[st][ed])printf("SOSO\n");else{if(d[st][u]+d[ed][v]+w==d[st][ed]){if(dp[st][u]*dp[ed][v]==dp[st][ed])printf("SAD\n");elseprintf("SOSO\n");}elseprintf("SOSO\n");}}}return 0; }

    ?

    總結

    以上是生活随笔為你收集整理的Gym - 101986F Pizza Delivery(最短路+DAG必经边)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。