• 缩点


    题目描述

    给定一个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
    ",maxx);
    }
    
    不要忘记努力,不要辜负自己 欢迎指正 QQ:1468580561
  • 相关阅读:
    学习之路-前端-笔记-一、HTML笔记
    抄写例题作业1
    郭霖
    java遍历HashMap的高效方法
    Add Two Numbers II 两个数字相加之二
    基于socket的简单p2p聊天项目
    SimpleScalar Course Project
    Dijkstra Java
    PCA vs Linear Regression 可视化理解
    机器学习中的范数规则化之(一)L0、L1与L2范数
  • 原文地址:https://www.cnblogs.com/smallocean/p/9805507.html
Copyright © 2020-2023  润新知