缩点

题目描述

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

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

输入输出格式

输入格式:

第一行,n,m

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

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

输出格式:

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

缩点,就是把一张有向有环图中的环缩成一个个点,形成一个有向无环图。根据题目意思,我们只需要找出一条点权最大的路径就行了,不限制点的个数。那么考虑对于一个环上的点被选择了,一整条环是不是应该都被选择,这一定很优,能选干嘛不选。很关键的是题目还允许我们重复经过某条边或者某个点,我们就不需要考虑其他了。因此整个环实际上可以看成一个点(选了其中一个点就应该选其他的点)

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define  ll long long
const int maxn=2e4+10;
const int maxm=2e5+7;
struct Edge{
    int to,next;
}e[maxm<<1];
int head[maxn],tol;
int low[maxn],dfn[maxn],stk[maxn],color[maxn];
int ind,top;
ll w[maxn];
ll val[maxn],vis[maxn];
int scc;
bool in_stk[maxn];
inline void add(int u,int v){
    tol++;e[tol].to=v;e[tol].next=head[u];head[u]=tol;
}
struct node{
    int x,y;
}s[maxm];
void tarjan(int u){
    int v;
    low[u]=dfn[u]=++ind;
    stk[top++]=u;
    in_stk[u]= true;
    for(int i=head[u];i;i=e[i].next){
        v=e[i].to;
        if(!dfn[v]){
            tarjan(v);
            if(low[u]>low[v]){
                low[u]=low[v];
            }
        }else if(in_stk[v]&&low[u]>dfn[v]){
            low[u]=dfn[v];
        }
    }
    if(low[u]==dfn[u]){
        scc++;
        do{
            v=stk[--top];
            in_stk[v]=false;
            color[v]=scc;
            w[scc]+=val[v];
        }while (v!=u);
    }
}
ll dfs(int u){
    if(!vis[u]) {
        vis[u]=w[u];
        for (int i = head[u]; i; i = e[i].next) {
            vis[u]=max(vis[u],dfs(e[i].to)+w[u]);
        }
    }
    return vis[u];
}
int main(){
     int n,m;scanf("%d%d",&n,&m);
    for (int i =1; i <=n ; ++i) {
        scanf("%lld",&val[i]);
    }
    for (int i =1; i <=m ; ++i) {
        scanf("%d%d",&s[i].x,&s[i].y);
        add(s[i].x,s[i].y);
    }
    for(int i=1;i<=n;++i){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    tol=0;
    memset(head,0,sizeof(head));
    for(int i=1;i<=m;++i){
        if(color[s[i].x]!=color[s[i].y]){
            add(color[s[i].x],color[s[i].y]);
        }
    }
    ll maxx=0;
    for(int i=1;i<=scc;++i){
        maxx=max(maxx,dfs(i));
    }
    printf("%lld\n",maxx);
}
posted @ 2018-10-17 17:26  house_cat  阅读(287)  评论(0编辑  收藏  举报