ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷 P3627 【抢掠计划】

2019-07-29 13:00:42  阅读:303  来源: 互联网

标签:连通 抢掠 vis int pru stu 500001 洛谷 P3627



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


细节问题 :

  • 关于如何把点权转化为边权:很简单,设u -> k有一条路,q[i]表示点i的权值,边的权值就是q[u],最后我们只需把q[最后一个点的权值(终点)]加上就好了。
  • 关于如何建边:只需把不在同一个强连通分量中的可以连接的边连起来就好了(注意:是连两个点所在的的强连通分量)。
  • 关于如何跑最长路:我们只学过最短路,但没学过该如何跑最长路,所以我们化未知变为已知,把最长路化为最短路。你们仔细想一想,如果我们把边权建为负的,是不是就可以跑最短路了?最后再把距离 * -1 不就完了?

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有