zoukankan      html  css  js  c++  java
  • [模板](luogu P3387)縮點

    前言:對於這週的咕咕咕表示好像沒什麼好表示的,完全沒有靈感a......寫東西真的好難啊......於是又玩了半天鬼泣4???還挺好玩的

    來源:題解


    题目背景

    缩点+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


    題目中給出了算法,然而第一篇題解用的是拓撲排序,所以我就照著抄了......

    本來寒假學過tarjan的,然而忘記了,這次複習一開始最看不懂的是low數組:

    low數組表示“從i點出發能訪問到的最早進入時間”,事實上是如果從i點出發能向上走到某個點說明這裡存在了一個環,從i發出了一條後向邊,

    等dfs完這個點的分支的時候,找到的環就會是最大的了。

    縮點就是每個強連通分量當做一個點,然後重新建圖

    #include<iostream>
    #include<cstdio>
    #include<queue>
    using namespace std;
    const int maxn=10000+15;
    int n,m,cnt,tim,top,s;
    int p[maxn],head[maxn],sd[maxn],dfn[maxn],low[maxn];
    //sd為這個點在哪個強連通分量中,dfs時間戳,
    //low棧中以u為父結點的子樹能連接到棧中最上端的點的dfs值
    //也就是從i點出發能訪問到的最早進入時間 
    //p為點權,in為入度 
    int stac[maxn],vis[maxn];//栈只为了表示此时是否有父子关系
    int h[maxn],in[maxn],dist[maxn]; 
    struct node{
        int u,v,next;
    }e[maxn*10],ed[maxn*10];
    void add(int u,int v)
    {
        e[++cnt].u=u;
        e[cnt].v=v;
        e[cnt].next=head[u];
        head[u]=cnt;
    }
    void tarjan(int x)//求強連通分量,每個強連通分量就是一個新點 
    {
        low[x]=dfn[x]=++tim;
        stac[++top]=x;vis[x]=1;
        
        for(int i=head[x];i;i=e[i].next){
            int v=e[i].v;
            if(!dfn[v]){
                tarjan(v);
                low[x]=min(low[x],low[v]);
            }
            else if(vis[v]){
                low[x]=min(low[x],low[v]);
            }
        }
        if(dfn[x]==low[x]){
            int y;
            while(y=stac[top--]){ 
                sd[y]=x;
                vis[y]=0;
                if(x==y)break;
                p[x]+=p[y];
            }
        }
    }
    //縮成了DAG圖,所以可以拓撲排序了 
    //可以直接dp 
    int topo()
    {
        queue<int>q;
        int tot=0;
        for(int i=1;i<=n;i++)
        if(sd[i]==i&&!in[i]){//自己是這個強連通分量的根 
            q.push(i);
            dist[i]=p[i];
        }
        while(!q.empty()){
            int k=q.front();q.pop();
            for(int i=h[k];i;i=ed[i].next){
                int v=ed[i].v;
                dist[v]=max(dist[v],dist[k]+p[v]);
                in[v]--;
                if(in[v]==0)q.push(v);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        ans=max(ans,dist[i]);
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        scanf("%d",&p[i]);
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
        }
        for(int i=1;i<=n;i++)
        if(!dfn[i])tarjan(i);
        for(int i=1;i<=m;i++){//重新建圖,枚舉每一條原邊,如果不在一個強連通分量里就連上 
            int x=sd[e[i].u],y=sd[e[i].v];
            if(x!=y){
                ed[++s].next=h[x];
                ed[s].v=y;
                ed[s].u=x;
                h[x]=s;
                in[y]++;
            }
        }
        printf("%d",topo());
    }
  • 相关阅读:
    CentOS7基础优化与常用配置
    MHA+binlogserver+VIP+sendreport 高可用架构
    GTID主从复制
    主从复制故障处理
    主从复制
    mysql 配置文件
    通用二进制安装mysql-5.7.28(无坑)
    css动画 文字闪烁效果
    cmd命令提示符大全(干货)
    JS实现手机摇一摇功能
  • 原文地址:https://www.cnblogs.com/superminivan/p/10512698.html
Copyright © 2011-2022 走看看