zoukankan      html  css  js  c++  java
  • 【模板】缩点

    题目背景

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

    #include <cstdio>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int maxn = 10010, maxm = 100010;
    
    int n, m, head[maxn],sum[maxn],du[maxn], nextt[maxm], to[maxm], tot = 1, a[maxn], scc[maxn], top, pre[maxn], low[maxn], dfs_clock;
    int Head[maxn], To[maxn], Nextt[maxn], Tot = 1, d[maxn], vis[maxn], ans;
    
    void Add(int x, int y)
    {
        To[Tot] = y;
        Nextt[Tot] = Head[x];
        Head[x] = Tot++;
    }
    
    void add(int x, int y)
    {
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    stack <int> s;
    
    void tarjan(int u)
    {
        pre[u] = low[u] = ++dfs_clock;
        s.push(u);
        for (int i = head[u]; i; i = nextt[i])
        {
            int v = to[i];
            if (!pre[v])
            {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else
                if (!scc[v])
                    low[u] = min(low[u], pre[v]);
        }
        if (pre[u] == low[u])
        {
            top++;
            while (1)
            {
                int t = s.top();
                s.pop();
                scc[t] = top;
                sum[top] += a[t];
                if (t == u)
                    break;
            }
        }
    }
    
    void spfa(int s)
    {
        memset(d, 0, sizeof(d));
        memset(vis, 0, sizeof(vis));
        d[s] = sum[s];
        vis[s] = 1;
        queue <int> q;
        q.push(s);
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for (int i = Head[u]; i; i = Nextt[i])
            {
                int v = To[i];
                if (d[v] < d[u] + sum[v])
                {
                    d[v] = sum[v] + d[u];
                    if (!vis[v])
                    {
                        vis[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
        for (int i = 1; i <= top; i++)
            ans = max(ans, d[i]);
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        for (int i = 1; i <= m; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            if (u != v)
            add(u, v);
        }
        for (int i = 1; i <= n; i++)
            if (!scc[i])
                tarjan(i);
        for (int i = 1; i <= n; i++)
            for (int j = head[i]; j; j = nextt[j])
            {
                int v = to[j];
                if (scc[i] != scc[v])
                {
                    Add(scc[i], scc[v]);
                    du[scc[v]]++;
                }
            }
        for (int i = 1; i <= top; i++)
            if (!du[i])
                spfa(i);
        printf("%d
    ", ans);
    
        return 0;
    }
  • 相关阅读:
    dxCalloutPopup 简单使用教程
    Delphi INI文件保存与读取
    AlertWindowManager 弹出提示窗口使用帮助(下)
    AlertWindowManager 弹出提示窗口使用帮助(上)
    可输入弹出窗口-[POPUP_GET_VALUES_USER_HELP]
    [BAPI]采购申请PR审批-BAPI_REQUISITION_RELEASE_GEN
    如何取域值 (当一些业务需要的值只有数字或者字母时 ,汉字描述在域里面)
    采购订单、采购申请审批策略相关表
    [BAPI]如何修改工单状态-BAPI_ALM_ORDER_MAINTAIN
    [函数]读取采购订单、采购申请更改历史-ME_CHANGEDOC_READ2
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7815936.html
Copyright © 2011-2022 走看看