zoukankan      html  css  js  c++  java
  • 缩点

    题目描述

    给定一个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
  • 相关阅读:
    从训练数据中随机抽取一打数据的好方法
    黄金坑的说明
    Chainer的初步学习
    split和strip的使用
    转载:configure执行流程(1.5.2)《深入理解Nginx》(陶辉)
    转载:编译安装Nginx(1.5.1)《深入理解Nginx》(陶辉)
    转载:编译安装Nginx(1.4)《深入理解Nginx》(陶辉)
    转载:获取Nginx源码(1.3.5)《深入理解Nginx》(陶辉)
    转载:Linux内核参数的优化(1.3.4)《深入理解Nginx》(陶辉)
    转载:磁盘目录(1.3.3)《深入理解Nginx》(陶辉)
  • 原文地址:https://www.cnblogs.com/smallocean/p/9805507.html
Copyright © 2011-2022 走看看