AlenaNuna

导航

Link With Running || 杭电多校第四场T2 || Dijkstra + Tarjan + SPFA

题面:http://acm.hdu.edu.cn/showproblem.php?pid=7175

题意:一个有向图,边权 ei 和 pi 。求从点 1 跑到点 n , 最小 Sum(ei) 是多少?在满足 Sum(ei) 最小的基础上,Sum(pi) 最大是多少?

ei 和 pi 大于等于 0。保证答案存在且可输出。

思路:

先用Dijkstra找最短路,然后再扫一遍找出最短路图。

由于e可为0,所以存在环。由于保证答案存在,所以不存在正环(否则没法找最长路。)即,存在且仅存在0环。

说白了就是逼着我们缩点。所以用Tarjan缩点。

然后缩完点后再建新图。新图为DAG。在该图上用SPFA找最长路(注意 Dijkstra没法找最长路。(一般情况))。由于该图为DAG,

所以可以使用入度优化大大提升效率。(否则会TLE)

代码:

  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 #define min(a,b) ((a)<(b)?(a):(b))
  4 using namespace std;
  5 const int maxn=1e5+10,maxm=3e5+10;
  6 const ll inf=(ll)1e18+7;
  7 int T,n,m,edge_head[maxn],num_edge,num_eg,eg_head[maxn];
  8 ll dis[maxn];
  9 int dfn[maxn],low[maxn],col[maxn],num_col,st[maxn],ix,tp,din[maxn];
 10 queue<int>que;
 11 bool vis[maxn];
 12 struct Node{
 13     int id,eg;
 14     ll dis;
 15     bool operator <(const Node&a)const{
 16         return (a.dis<dis);
 17     }
 18 }nd;
 19 priority_queue<Node>q;
 20 struct Edge{
 21     int from,to,nx;
 22     ll e,p;
 23 }edge[maxm],eg[maxm];
 24 void Add_edge(int from,int to,ll e,ll p){
 25     edge[++num_edge].nx=edge_head[from];
 26     edge[num_edge].from=from;
 27     edge[num_edge].to=to;
 28     edge[num_edge].e=e;
 29     edge[num_edge].p=p;
 30     edge_head[from]=num_edge;
 31     return;
 32 }
 33 void Add_eg(int i){
 34     int from=edge[i].from,to=edge[i].to,p=edge[i].p;
 35     eg[++num_eg].nx=eg_head[from];
 36     eg[num_eg].from=from;
 37     eg[num_eg].to=to;
 38     eg[num_eg].p=p;
 39     eg_head[from]=num_eg;
 40     return;
 41 }
 42 void Dij(){
 43     while(!q.empty()) q.pop();
 44     nd.id=1;nd.dis=0;
 45     q.push(nd);
 46     dis[1]=0;
 47     for(int i=2;i<=n;i++) dis[i]=inf;
 48     while(!q.empty()){
 49         nd=q.top();
 50         q.pop();
 51         int u=nd.id;
 52         if(vis[u]){
 53             if(u==n) break;
 54             continue;
 55         }
 56         vis[u]=1;
 57         for(int i=edge_head[u];i;i=edge[i].nx){
 58             int v=edge[i].to;
 59             if(dis[u]+edge[i].e<dis[v]){
 60                 dis[v]=dis[u]+edge[i].e;
 61                 nd.id=v; nd.dis=dis[v];
 62                 nd.eg=i;
 63                 q.push(nd);
 64             }
 65         }
 66     }
 67 
 68     for(int u=1;u<=n;u++){
 69         if(dis[u]==inf) continue;
 70         for(int i=edge_head[u];i;i=edge[i].nx){
 71             int v=edge[i].to;
 72             if(dis[u]+edge[i].e==dis[v]) Add_eg(i);
 73         }
 74     }
 75     return;
 76 }
 77 void Tarjan(int x){
 78     st[++tp]=x;
 79     vis[x]=1;
 80     dfn[x]=low[x]=++ix;
 81     for(int i=eg_head[x];i;i=eg[i].nx){
 82         int y=eg[i].to;
 83         if(dfn[y]==0){
 84             Tarjan(y);
 85             low[x]=min(low[x],low[y]);
 86         }
 87         else if(vis[y]) low[x]=min(low[x],dfn[y]);
 88     }
 89     if(dfn[x]==low[x]){
 90         num_col++;
 91         do{
 92             vis[st[tp]]=0;
 93             col[st[tp]]=num_col;
 94             tp--;
 95         }while(st[tp+1]!=x);
 96     }
 97     return;
 98 }
 99 void Work(){
100     num_edge=0;
101     memset(edge_head,0,sizeof(edge_head));
102     for(int i=1;i<=num_eg;i++){
103         int u=eg[i].from,v=eg[i].to;
104         if(col[u]!=col[v])
105             Add_edge(col[u],col[v],0,eg[i].p),din[col[v]]++;
106     }
107     return;
108 }
109 void SPFA(){
110     que.push(col[1]);
111     dis[col[1]]=0;
112     while(!que.empty()){
113         int x=que.front();
114         que.pop();
115         for(int i=edge_head[x];i;i=edge[i].nx){
116             int y=edge[i].to;
117             if(dis[y]<dis[x]+edge[i].p)
118                 dis[y]=dis[x]+edge[i].p;
119             if(--din[y]==0) que.push(y);//DAG优化。
120         }
121     }
122     return;
123 }
124 int main(){
125     scanf("%d",&T);
126     while(T--){
127         num_edge=0;num_eg=0;
128         memset(edge_head,0,sizeof(edge_head));
129         memset(eg_head,0,sizeof(eg_head));
130         //init
131 
132         scanf("%d%d",&n,&m);
133         int a,b; ll c,d;
134         for(int i=1;i<=m;i++){
135             scanf("%d%d%lld%lld",&a,&b,&c,&d);
136             Add_edge(a,b,c,d);
137         }
138         //从1到n最短路dij
139         Dij();
140         printf("%lld ",dis[n]);
141         //init
142         num_col=0;
143         tp=ix=0;
144         memset(vis,0,sizeof(vis));
145         memset(dfn,0,sizeof(dfn));
146         memset(low,0,sizeof(low));
147         memset(st,0,sizeof(st));
148         //init
149         Tarjan(1);
150         //init
151         memset(din,0,sizeof(din));
152         memset(dis,0,sizeof(dis));
153         //init;
154         Work();
155         SPFA();
156         printf("%lld\n",dis[col[n]]);
157     }
158     return 0;
159 }
View Code

By: AlenaNuna

posted on 2022-08-02 02:19  AlenaNuna  阅读(57)  评论(0编辑  收藏  举报