给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

因为可以重复经过点,所以一个点所在的强联通分量必定可以到达。所以直接缩点即可。

缩点之后,我们要让权值最大化,必须从入度为0的点开始搜。因为这是DAG,入度不为零的点的最后祖先必定是入度为零的点。由于这道题没有负数权值,从入度为零的结点开始走肯定是一个最好的选择。然后DAG上跑动归即可。

 #include <cstdio>
#include <cstring>
using namespace std; const int maxn=1e4+, maxm=1e5+; class Graph{
public:
//为什么用嵌套类,因为声明很烦。。并不是访问问题的原因。
//如果类的成员不是static的话,内部类是不知道获取哪个外部类对象的。。
//所以无论是把类放在里面还是外面,访问都有问题。
//另外,把private放在下面,应该是因为嵌套类类必须完全声明才能使用吧。。
//我也不大清楚。。先这么用着,以后再去翻c++ primer。
class Edge{
private:
Graph *belong;
public:
int v, to, next; //感觉这里还是不优雅。。
Edge(){}
Edge(Graph& g, int x, int y, int z){
belong=&g;
to=x, v=y, next=z;
}
Edge operator ++(){ //不能打引用!
*this=belong->edge[next]; //因为有自增运算,这个edge不能等同于图中的!
return *this;
}
int operator *(){
return to;
}
};
Graph(){}
void addedge(int x, int y, int v){
++cntedge;
edge[cntedge]=Edge(*this, y, v, fir[x]);
fir[x]=cntedge;
return;
}
Edge get_link(int x){ //这里改成begin较好
return edge[fir[x]];
}
private:
int cntedge, fir[maxn];
Edge edge[maxm];
}; int n, m, cnttime, cntscc;
int v[maxn], visit[maxn], time[maxn];
int scc[maxn], vofscc[maxn], in[maxn], ans[maxn];
Graph g, g_t, g_scc; void dfs(int now, int flag){
visit[now]=;
Graph::Edge e=g.get_link(now);
if (flag==) e=g_t.get_link(now);
int to=*e;
while (to){
if (!visit[to]) dfs(to, flag);
to=*(++e);
}
if (flag==){
++cnttime;
time[cnttime]=now;
}
if (flag==) {
scc[now]=cntscc;
vofscc[cntscc]+=v[now];
}
return;
} void dfs2(int x){
Graph::Edge e=g.get_link(x);
int to=*e;
visit[x]=;
while (to){
if (scc[to]!=scc[x]){
g_scc.addedge(scc[x], scc[to], v[scc[to]]);
++in[scc[to]];
}
if (!visit[to])
dfs2(to);
to=*(++e);
}
return;
} void dfs3(int x){
Graph::Edge e=g_scc.get_link(x);
int to=*e;
visit[x]=;
ans[x]=vofscc[x];
while (to){
if (!visit[to]) dfs3(to);
if (ans[to]+vofscc[x]>ans[x])
ans[x]=ans[to]+vofscc[x];
to=*(++e);
}
return;
} int main(){
scanf("%d%d", &n, &m);
for (int i=; i<=n; ++i)
scanf("%d", &v[i]);
int x, y;
for (int i=; i<=m; ++i){
scanf("%d%d", &x, &y);
g.addedge(x, y, );
g_t.addedge(y, x, );
} //建图
for (int i=; i<=n; ++i)
if (!visit[i]) dfs(i, ); //时间戳
memset(visit, , sizeof(visit));
for (int i=n; i>; --i){
if (!visit[time[i]]){
++cntscc;
dfs(time[i], );
}
} //求强联通分量
memset(visit, , sizeof(visit));
for (int i=; i<=n; ++i){
if (!visit[i]) dfs2(i);
} //缩点
for (int i=; i<=cntscc; ++i)
if (!in[i]) g_scc.addedge(, i, vofscc[i]); //超级源汇
memset(visit, , sizeof(visit));
dfs3(); //树形dp
printf("%d\n", ans[]);
return ;
}

洛谷P3387 缩点模板的更多相关文章

  1. 洛谷P3387缩点

    传送门 有向图.. 代码中有两种方法,拓扑排序和记忆化搜索 #include <iostream> #include <cstdio> #include <cstring ...

  2. 洛谷P3387 【模板】缩点 题解

    背景 今天\(loj\)挂了,于是就有了闲情雅致来刷\(luogu\) 题面 洛谷P3387 [模板]缩点传送门 题意 给定一个\(n\)个点\(m\)条边有向图,每个点有一个权值,求一条路径,使路径 ...

  3. 洛谷 P3387 【模板】缩点 DAGdp学习记

    我们以洛谷P3387 [模板]缩点 来学习DAGdp 1.这道题的流程 //伪代码 for i->n if(i未被遍历) tarjan(i) 缩点() DAGdp() 完成 首先tarjan这部 ...

  4. tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows

    缩点练习 洛谷 P3387 [模板]缩点 缩点 解题思路: 都说是模板了...先缩点把有环图转换成DAG 然后拓扑排序即可 #include <bits/stdc++.h> using n ...

  5. 【洛谷P3369】【模板】普通平衡树题解

    [洛谷P3369][模板]普通平衡树题解 题目链接 题意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3 ...

  6. 【洛谷4721】【模板】分治FFT(CDQ分治_NTT)

    题目: 洛谷 4721 分析: 我觉得这个 "分治 FFT " 不能算一种特殊的 FFT ,只是 CDQ 分治里套了个用 FFT (或 NTT)计算的过程,二者是并列关系而不是偏正 ...

  7. 【洛谷3865】 【模板】ST表(猫树)

    传送门 洛谷 Solution 实测跑的比ST表快!!! 这个东西也是\(O(1)\)的,不会可以看我上一篇Blog 代码实现 代码戳这里

  8. 洛谷——P3387 【模板】缩点

    P3387 [模板]缩点 题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点, ...

  9. 【模板】缩点(Tarjan算法)/洛谷P3387

    题目链接 https://www.luogu.com.cn/problem/P3387 题目大意 给定一个 \(n\) 个点 \(m\) 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之 ...

随机推荐

  1. C#中在内容页获取其模板页中的变量,或者值

    在CSDN的博文中看到了 muziduoxi 的文章:http://blog.csdn.net/muziduoxi/article/details/5386543 虽然里面提到的方法没有解决我的难题, ...

  2. PHP不用第三变量交换2个变量的值的解决方法

    以前做过一道php面试题是这样的:不使用第三个变量实现交换两个变量的值.一般都是借助第三个中间变量来实现原来两个变量的值交换,但是这道题却要求不能使用中间变量,这对于初学者来说也算是一个难题了.网上找 ...

  3. 高并发下用pdo,文件排它锁,redis三种方法对比

    <?php header('content-type:text/html;charset=utf-8');                 // //无控制     // $DB_DSN = ' ...

  4. python字符串相关操作

    字符串搜索相关搜索指定字符串,没有返回-1:str.find('t')指定起始位置搜索:str.find('t',start)指定起始及结束位置搜索:str.find('t',start,end)从右 ...

  5. 判断CPU是大端还是小端

    #include "stdafx.h" #include <iostream> using namespace std; /* #大端模式(Big_endian):字数 ...

  6. Debian for ARM

    /************************************************************************* * Debian for ARM * 说明: * ...

  7. Aravis 库编译方法

    Aravis 库编译方法 March 21, 2015 9:40 PM 首先下载 aravis 库的源代码:aravis 库下载地址 这里我们使用的是 aravis_0_2_0,比较老的一个版本. 首 ...

  8. JS通过经纬度计算两个地方的距离

    1 主要原理: Lat1 Lung1 表示A点纬度和经度,Lat2 Lung2 表示B点纬度和经度: a=Lat1 – Lat2 为两点纬度之差  b=Lung1 -Lung2 为两点经度之差: 63 ...

  9. html之ajax

    正常情况下,html中的ajax(也就是XMLHttpRequest对象)是不能跨域的.(特殊情况,此处不讨论,请网上Google) ---跨域:是url的协议或ip或端口,其中有一个不同,就是跨域. ...

  10. Poj 1401 Factorial(计算N!尾数0的个数——质因数分解)

    一.Description The most important part of a GSM network is so called Base Transceiver Station (BTS). ...