码迷,mamicode.com
首页 > 其他好文 > 详细

P3387 【模板】缩点

时间:2019-07-09 14:04:30      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:scan   模板   struct   bool   while   ace   重复   top   amp   

题目背景

缩点+DP

题目描述

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

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

输入输出格式

输入格式:

 

第一行,n,m

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

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

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制
2 2
1 1
1 2
2 1
输出样例#1: 复制
2

说明

n<=10^4,m<=10^5,0<=点权<=1000

算法:Tarjan缩点+DAGdp

 

#include<bits/stdc++.h>
using namespace std;
struct edge{
    int nw,nxt,mark;
}pre[100010];
int n,m,idx,cnt;
int dfn[10010],low[10010];
int in[10010],v[10010],fa[10010];
int head[10010];
bool used[10010];
int stk[10010],p;
int ans=0;
void add (int x,int y,int cnt)
{
    pre[cnt].nw=x;
    pre[cnt].mark=head[x];
    pre[cnt].nxt=y;
    head[x]=cnt;
}
void tarjan (int u)
{
    dfn[u]=low[u]=++idx;
    stk[++p]=u;
    used[u]=1;
    for (int i=head[u];i!=0;i=pre[i].mark)
    {
        int nx=pre[i].nxt;
        if (!dfn[nx])
        {
            tarjan (nx);
            low[u]=min (low[u],low[nx]);
        }
        else if (used[nx])
            low[u]=min (low[u],dfn[nx]);
    }
    if (low[u]==dfn[u])
    {
        do{
            v[u]+=v[stk[p]];
            fa[stk[p]]=u;
            used[stk[p]]=0;
            p--;
        }while (stk[p+1]!=u);
        v[u]>>=1;
    }
}
int topo ()
{
    int dis[10010];
    queue<int>q;
    for (int i=1;i<=n;i++)
        if (fa[i]==i)
        {
            dis[i]=v[i];
            if (!in[i])
                q.push(i);
        }
    while (!q.empty())
    {
        int Now=q.front();
        for (int i=head[Now];i!=0;i=pre[i].mark)
        {
            int Nxt=pre[i].nxt;
            dis[Nxt]=max (dis[Nxt],dis[Now]+v[Nxt]);
            in[Nxt]--;
            if (!in[Nxt])
                q.push (Nxt);
        }
        q.pop();
    }
    int maxx=0;
    for (int i=1;i<=n;i++)
        if (fa[i]==i)
            maxx=max (maxx,dis[i]);
    return maxx;
}
int main()
{
    memset (in,0,sizeof (in));
    memset (used,0,sizeof (used));
    memset (dfn,0,sizeof(dfn));
    memset (head,0,sizeof (head));
    scanf ("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf ("%d",&v[i]);
    for (int i=1;i<=m;i++)
    {
        int a,b;
        scanf ("%d%d",&a,&b);
        add (a,b,i);
    }
    for (int i=1;i<=n;i++)
        if (!dfn[i])
            tarjan (i);
    memset (head,0,sizeof (head));
    for (int i=1;i<=m;i++)
    {
        int Now=fa[pre[i].nw];
        int Nxt=fa[pre[i].nxt];
        if (Now!=Nxt)
        {
            add (Now,Nxt,++cnt);
            in[Nxt]++;
        }
    }
    printf ("%d",topo ());
    return 0;
}

  

P3387 【模板】缩点

标签:scan   模板   struct   bool   while   ace   重复   top   amp   

原文地址:https://www.cnblogs.com/xiongchongwen/p/11156581.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!