Description

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

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

Input&Output

Input

第一行,n,m

第二行,n个整数,依次代表点权

第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

Output

共一行,最大的点权之和。

Sample

Input

2 2
1 1
1 2
2 1

Output

2

Solution

对于一个联通块,一定是经过其中所有点是最优的,所以我们可以缩点,新的点权是联通块内的点权和。

缩点后会得到一个DAG,此时一定是从入度为零的点走到出度为零的点最优,证明略。所以记录一下拓扑序,再做DP即可。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
#define maxe 100005
#define maxn 10005
using namespace std;
struct edge{
    int to,nxt;
}e[maxe];
struct cedge{
    int to,nxt;
}ce[maxe];
int edgenum,cedgenum,lnk[maxn],clnk[maxn],k[maxn],a,b,n,m;
int dfn[maxn],low[maxn],dgr[maxn],cnt,num,blk[maxn],sz[maxn];
int f[maxn];
int hd=0,tl=1,q[maxn];
bool vis[maxn];
stack<int> st;
void add(int bgn,int end)
{
    e[++edgenum].to=end;
    e[edgenum].nxt=lnk[bgn];
    lnk[bgn]=edgenum;
}
void c_add(int bgn,int end)
{
    ce[++cedgenum].to=end;
    ce[cedgenum].nxt=clnk[bgn];
    clnk[bgn]=cedgenum;
    dgr[end]++;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++cnt;
    vis[x]=1;st.push(x);
    for(int p=lnk[x];p;p=e[p].nxt){
        int y=e[p].to;
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(vis[y])
            low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x]){
        int now;
        num++;
        do{
            now=st.top();st.pop();
            vis[now]=0;
            blk[now]=num;
        }while(now!=x);
    }
}
void toposort()
{
    for(int i=1;i<=num;++i){
        f[i]=sz[i];
        if(!dgr[i])q[tl++]=i;
    }
    while(++hd<tl){
        int u=q[hd];
        for(int p=clnk[u];p;p=ce[p].nxt){
            int y=ce[p].to;
            if(!--dgr[y])q[tl++]=y;
        }
    }
}
void solve()
{
    hd=0;
    while(++hd<tl){
        int u=q[hd];
        for(int p=clnk[u];p;p=ce[p].nxt){
            int y=ce[p].to;
            f[y]=max(f[y],f[u]+sz[y]);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        scanf("%d",&k[i]);
    for(int i=1;i<=m;++i)
        scanf("%d%d",&a,&b),add(a,b);
    for(int i=1;i<=n;++i)
        if(!dfn[i])tarjan(i);
    for(int i=1;i<=n;++i){
        sz[blk[i]]+=k[i];
        for(int p=lnk[i];p;p=e[p].nxt){
            int y=e[p].to;
            if(blk[i]!=blk[y])c_add(blk[i],blk[y]);
        }
    }
    toposort();
    solve();
    int maxans=0;
    for(int i=1;i<=num;++i)
        maxans=max(maxans,f[i]);
    printf("%d\n",maxans);
    return 0;
}

[模板][Luogu3387] 缩点 - Tarjan, 拓扑+DP的更多相关文章

  1. P3387缩点(tarjan+拓扑排序+线性dp)

    题目描述 给定一个 n个点 m 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次. 输入 ...

  2. P3387 【模板】缩点 tarjan

    虽说是模板题,但是竟然中间有dp的部分...先tarjan缩点,重新建图.然后记忆化搜索,搜索dag中的最小环. 题干: 题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值, ...

  3. 【模板】缩点(tarjan,DAG上DP)

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

  4. 【模板】缩点 tarjan+dp

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

  5. 【Luogu P3387】缩点模板(强连通分量Tarjan&拓扑排序)

    Luogu P3387 强连通分量的定义如下: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶 ...

  6. bzoj 2208: [Jsoi2010]连通数【tarjan+拓扑+dp】

    我总觉得枚举点bfs也行-- tarjan缩点,记一下每个scc的size,bitset压一下scc里的点,然后按拓扑倒序向上合并到达状态,然后加ans的时候记得乘size #include<i ...

  7. BZOJ 1093 强连通缩点+DAG拓扑DP

    缩点后在一个DAG上求最长点权链 和方案数 注意转移条件和转移状态 if (nowmaxn[x] > nowmaxn[v]) { ans[v] = ans[x]; nowmaxn[v] = no ...

  8. luogu P3387 【模板】缩点_拓扑排序

    还是很好些的. Code: #include <stack> #include <cstdio> #include <algorithm> #include < ...

  9. 【tarjan 拓扑排序 dp】bzoj1093: [ZJOI2007]最大半连通子图

    思维难度不大,关键考代码实现能力.一些细节还是很妙的. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于 ...

随机推荐

  1. spark source code 分析之ApplicationMaster overview(yarn deploy client mode)

    一直不是很清楚ApplicationMaster的作用,尤其是在yarn client mode和cluster mode的区别 网上有一些非常好的资料,请移步: https://blog.cloud ...

  2. 原生js实现简单的全屏滚动

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Maven-06: 插件的内置绑定

    Maven的生命周期与插件相互绑定,用以完成实际的构建任务.具体而言,是生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务.例如项目编译这一任务,它对应default生命周期的compile ...

  4. 计时器setInterval()-慕课网

    计时器setInterval() 在执行时,从载入页面后每隔指定的时间执行代码. 语法: setInterval(代码,交互时间); 参数说明: 1. 代码:要调用的函数或要执行的代码串. 2. 交互 ...

  5. jmeter连接Mysql数据库测试性能初探

    Jmeter mysql性能测试演示 1.  Jmeter是java开发的,jmeter连接mysql数据库当然需要jdbc驱动,这个可以在网上下载mysql-connector-java包,然后解压 ...

  6. 设计模式之 观察者模式详解(包含观察者模式JDK的漏洞以及事件驱动模型)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 本章我们讨论一个除前面的单例 ...

  7. Ubuntu16.0.4的磁盘管理

    ubuntu下硬盘无损分区移动修改工具 原创 2014年04月13日 :: ubuntu上面其实有很好的分区调整工具,gparted,非常好使用 安装非常简单 sudo apt-get install ...

  8. linux,windows,ubuntu下git安装与使用

    ubuntu下git安装与使用:首先应该检查本地是否已经安装了git ,如果没有安装的话,在命令模式下输入 sudo apt-get install git 进行安装 输入git命令查看安装状态及常用 ...

  9. alpha冲刺第三天

    一.合照 二.项目燃尽图 三.项目进展 今天是一个瓶颈期,在昨天被困住的地方今天还是没能解决,所以今天的项目进展并没有发生什么变化. 今天晚上xl和lj去实验室找学姐了,在学姐的帮助下大概有了一点思路 ...

  10. 利用python实现简单邮件功能

    #!/usr/bin/env python # -*- coding:utf-8 -*- import smtplib from email.utils import formataddr from ...