Gym - 101986F Pizza Delivery(最短路+DAG必经边)
生活随笔
收集整理的這篇文章主要介紹了
Gym - 101986F Pizza Delivery(最短路+DAG必经边)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接:點擊查看
題目大意:給出一個n個點m條邊的有向無環圖,每條邊的權重為w,起點為1,終點為2,現在對每一條邊詢問:
若將該邊的方向取反,權值不變,則對最短路有無影響,分為三種情況討論:
題目分析:我們可以用迪杰斯特拉,用正向邊跑一下起點的最短路,再用反向邊跑一下終點的最短路,然后在枚舉每條邊即可,我們假設d[st][i]是起點到點i的最短路,d[ed][i]是點i到終點的最短路,w為每條邊的權值
當d[st][v]+d[ed][u]+w<d[st][ed]時,直接輸出HAPPY即可
但是判斷SOSO和SAD就有點麻煩了,因為最短路不止有一條,我們分兩種情況討論:
這里就涉及到了該如何求最短路的必經邊呢?網上說可以用支配樹來做,也可以用dp來做,我不會支配樹,就說一下怎么用dp做吧
因為是有向邊,所以我們可以拓撲排序一下,利用樹形dp的思想,每次給接下來的節點累加上當前的答案,從起點跑一邊,再從終點跑一邊,設dp[st][i]是從起點到點i的路線數,dp[ed][i]是從點i到終點的路線數,那么若當前邊/點為必經邊/點,需要滿足:
有了這個前置知識后,我們就可以輕松解決這個題目了,不過實現起來會很惡心人,注意一下要靜下心來慢慢寫,不然一處小細節可能就得調上一下午
代碼:
#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必经边)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (转)三大博弈定义+结论
- 下一篇: HDU - 3571 HDU CakeM