洛谷 P3387 【模板】缩点

来源:互联网 发布:泰瑞克埃文斯生涯数据 编辑:程序博客网 时间:2024/06/05 20:25

题目背景

缩点+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,|点权|<=1000 算法:Tarjan缩点+DAGdp
去你的dp
我来一波spfa

#include <cstdio>#include <iostream>#include <queue>#include <algorithm>#include <cstring>#define N 100005using namespace std;int dfn[N],low[N];int siz[N],val[N],head[N];int n,m,tot;bool vis[N];int topp;int stac[N];int cnt;int rd[N];int col[N];int bel[N];int VAL[N];struct EDGE{    int nex,to,fa;}ed[N*2];int dfs_clock;void tarjan(int u){    dfn[u]=low[u]=++dfs_clock;    stac[++topp]=u;    vis[u]=true;    for(int i=head[u];i;i=ed[i].nex){        int dmf=ed[i].to;        if(!dfn[dmf]){            tarjan(dmf);            low[u]=min(low[u],low[dmf]);        }        else if(vis[dmf]) low[u]=min(low[u],dfn[dmf]);    }    if(dfn[u]==low[u]){        vis[u]=false;          VAL[bel[u]=++cnt]+=val[u];          while(stac[topp]!=u){            vis[stac[topp]]=false;            bel[stac[topp]]=cnt;            VAL[cnt]+=val[stac[topp]];            topp--;        }        topp--;    }}inline void add(int x,int y){    ++tot;    ed[tot].nex=head[x];    head[x]=tot;    ed[tot].to=y;}int dis[N];int ans=0;bool vv[N];int head2[N];int to2[N];int nex2[N];inline void spfa(int u){    queue<int >q;    memset(dis,0,sizeof(dis));    memset(vv,0,sizeof(vv));    q.push(u);    dis[u]=VAL[u];    vis[u]=1;    while(!q.empty()){        int dmf=q.front();        q.pop();        vv[dmf]=0;        for(int i=head2[dmf];i;i=nex2[i]){            int hxr=to2[i];            if(dis[hxr]<dis[dmf]+VAL[hxr]){                dis[hxr]=dis[dmf]+VAL[hxr];                if(!vv[hxr]){                   vv[hxr]=true;                   q.push(hxr);                }            }        }    }    for(int i=1;i<=cnt;i++) ans=max(ans,dis[i]);}int zong;inline void add2(int x,int y){    ++zong;    nex2[zong]=head2[x];    head2[x]=zong;    to2[zong]=y;}inline void rebuild(){    for(int i=1;i<=n;i++){       for(int j=head[i];j;j=ed[j].nex){           if(bel[ed[j].to]!=bel[i]){                add2(bel[i],bel[ed[j].to]);           }       }    }}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++){        scanf("%d",&val[i]);    }    for(int i=1;i<=m;i++){        int x,y;        scanf("%d%d",&x,&y);        add(x,y);    }    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);    rebuild();    for(int i=1;i<=cnt;i++){        spfa(i);    }    printf("%d",ans);    return 0;}
原创粉丝点击