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 }
By: AlenaNuna