其他分享
首页 > 其他分享> > 洛谷 P3627 【抢掠计划】

洛谷 P3627 【抢掠计划】

作者:互联网


思路 : 这道题是一道Tarjan + 最长路的题。首,我们用Tarjan把每个强连通分量缩成一个点,并记录那个强连通分量的点权和(因为当那个人走进一个强连通分量后那个强连通分量中的所有money都会被他拿走(绕一圈不就完了?)),然后我们化点权为边权,再以起点所在的强连通分量跑最长路,最后就能计算出从起点所在的强连通分量到任意一个终点所在的强连通分量的最长距离了(最大money值),输出的是取从起点所在的强连通分量到任意一个终点所在的强连通分量的最大值。


细节问题 :


code:

  1 #include <bits/stdc++.h>
  2 #define INF 0x3f3f3f3f
  3 using namespace std;
  4 stack < int > pru;
  5 int n, m, p, head[500001], q[500001], col[500001], color, dfn[500001], low[500001], s, e[500001], sum[500001], z, num, vis[500001], dis[500001], ans;//变量太多懒得解释,意会一下吧。。。 
  6 struct node//存边 
  7 {
  8     int next, to, val;
  9 }stu[500001];
 10 queue < node > G;//用于临时存放边 
 11 inline void add(int x, int y, int z)
 12 {
 13     stu[++num].next = head[x];
 14     stu[num].to = y;
 15     stu[num].val = z;
 16     head[x] = num;
 17     return;
 18 }
 19 inline void tarjan(int u)//Tarjan算法,这里用于缩点 
 20 {
 21     dfn[u] = low[u] = ++z;
 22     vis[u] = 1;
 23     pru.push(u);
 24     for(register int i = head[u]; i; i = stu[i].next)
 25     {
 26         int k = stu[i].to;
 27         if(!vis[k])
 28         {
 29             tarjan(k);
 30             low[u] = min(low[u], low[k]);
 31         }
 32         else if(!col[k])
 33         {
 34             low[u] = min(low[u], dfn[k]);
 35         }
 36     }
 37     if(dfn[u] == low[u])
 38     {
 39         col[u] = ++color;
 40         sum[color] += q[u];//权值和 
 41         while(pru.top() != u)
 42         {
 43             col[pru.top()] = color;
 44             sum[color] += q[pru.top()];//权值和 
 45             pru.pop();
 46         }
 47         pru.pop();
 48     }
 49     return;
 50 }
 51 inline void spfa(int s)//求最短路模板SPFA 
 52 {
 53     queue < int > pru;
 54     memset(vis, 0, sizeof(vis));
 55     memset(dis, INF, sizeof(dis));
 56     pru.push(s);
 57     dis[s] = 0;
 58     vis[s] = 1;
 59     while(!pru.empty())
 60     {
 61         int u = pru.front();
 62         pru.pop();
 63         vis[u] = 0;
 64         for(register int i = head[u]; i; i = stu[i].next)
 65         {
 66             int k = stu[i].to;
 67             if(dis[k] > dis[u] + stu[i].val)
 68             {
 69                 dis[k] = dis[u] + stu[i].val;
 70                 if(!vis[k])
 71                 {
 72                     vis[k] = 1;
 73                     pru.push(k);
 74                 }
 75             }
 76         }
 77     }
 78     return;
 79 }
 80 inline void init()//初始化 
 81 {
 82     memset(head, 0, sizeof(head));
 83     for(register int i = 1; i <= 100000; ++i)
 84     {
 85         stu[i].next = 0;
 86         stu[i].to = 0;
 87         stu[i].val = 0;
 88     }
 89     num = 0;
 90     return;
 91 }
 92 inline void add_edge()
 93 {
 94     for(register int u = 1; u <= n; ++u)
 95     {
 96         for(register int i = head[u]; i; i = stu[i].next)
 97         {
 98             int k = stu[i].to;
 99             if(col[k] != col[u])//不在一个强连通分量中才建边 
100             {
101                 //需要临时先放到G里,因为如果还没有把那些一大堆东西初始化就又建边,会....... 
102                 G.push(node{col[u], col[k], -sum[col[u]]});//要建负边权(这样可以把最长路转化为最短路) 
103             }
104         }
105     }
106     init();//初始化 
107     while(!G.empty())//初始化完再存边 
108     {
109         node p = G.front();
110         add(p.next, p.to, p.val);//建边 
111         G.pop();
112     }
113     return;
114 }
115 signed main()
116 {
117     scanf("%d %d", &n, &m);
118     for(register int i = 1, x, y; i <= m; ++i)
119     {
120         scanf("%d %d", &x, &y);
121         add(x, y, 0);
122     }
123     for(register int i = 1; i <= n; ++i)
124     {
125         scanf("%d", &q[i]);
126     }
127     scanf("%d %d", &s, &p);
128     for(register int i = 1; i <= p; ++i)
129     {
130         scanf("%d", &e[i]);
131     }
132     for(register int i = 1; i <= n; ++i)
133     {
134         if(!vis[i])
135         {
136             tarjan(i);
137         }
138     }
139     add_edge();//建边 
140     spfa(col[s]);//从起点所在的强连通分量中开始 
141     for(register int i = 1; i <= p; ++i)
142     {
143         ans = max(ans, dis[col[e[i]]] * -1/*别忘了把它变回正数*/ + sum[col[e[i]]]/*别加上终点所在的强联通分量的权值*/);
144     }
145     printf("%d", ans);
146     return 0;
147 }

 

标签:连通,抢掠,vis,int,pru,stu,500001,洛谷,P3627
来源: https://www.cnblogs.com/qqq1112/p/11255179.html