• P3387 【模板】缩点 tarjan


    虽说是模板题,但是竟然中间有dp的部分...先tarjan缩点,重新建图.然后记忆化搜索,搜索dag中的最小环.

    题干:

    题目背景
    
    缩点+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<iostream>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define duke(i,a,n) for(int i = a;i <= n;i++)
    #define lv(i,a,n) for(int i = a;i >= n;i--)
    #define clean(a) memset(a,0,sizeof(a))
    const int INF = 1 << 30;
    typedef long long ll;
    typedef double db;
    template <class T>
    void read(T &x)
    {
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x)
    {
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    int lst[100010],dfn[100010],low[100010],n,m,tot = 0,str[100010],top = 0,vis[100010];
    int num[100010],chu[100010],col[100010],len = 0,ans = 0,ru[100001];
    int hr[100010],kk[100010],f[100010];
    struct node
    {
        int l,r,nxt;
    }a[100010];
    void add(int x,int y)
    {
        a[++len].l = x;
        a[len].r = y;
        a[len].nxt = lst[x];
        lst[x] = len;
    }
    void tarjan(int x)
    {
        dfn[x] = low[x] = ++tot;
        str[++top] = x;
        vis[x] = 1;
        for(int k = lst[x];k;k = a[k].nxt)
        {
            int y = a[k].r;
            if(!dfn[y])
            {
                tarjan(y);
                low[x] = min(low[x],low[y]);
            }
            else if(vis[y])
            {
                low[x] = min(low[x],dfn[y]);
            }
        }
        if(low[x] == dfn[x])
        {
            ans++;
            int v;
            do
            {
                num[ans]++;
                vis[str[top]] = 0;
                v = str[top--];
                col[v] = ans;
                kk[ans] += hr[v];
            }
            while(x != v);
        }
    }
    void search(int x)
    {
        if(f[x])
        return;
        int maxnum = 0;
        f[x] = kk[x];
        for(int k = lst[x];k;k = a[k].nxt)
        {
            int y = a[k].r;
            if(!f[y])
            search(y);
            maxnum = max(maxnum,f[y]);
        }
        f[x] += maxnum;
    }
    int main()
    {
        read(n);read(m);
        duke(i,1,n)
        {
            read(hr[i]);
        }
        duke(i,1,m)
        {
            int x,y;
            read(x);read(y);
            add(x,y);
        }
        duke(i,1,n)
        {
            if(!dfn[i])
            tarjan(i);
        }
        clean(lst);
        int u = len;
        len = 0;
        duke(i,1,u)
        {
            if(col[a[i].l] != col[a[i].r])
            {
                add(col[a[i].l],col[a[i].r]);
            }
        }
        int maxn = 0;
        duke(i,1,ans)
        {
            if(f[i] == 0)
            {
                search(i);
                maxn = max(maxn,f[i]);
            }
        }
        printf("%d
    ",maxn);
        return 0;
    }
    /*
    2 2
    1 1
    1 2
    2 1
    */
  • 相关阅读:
    iscroll中使用input框的话是导致无法选中input框
    JS中setInterval()和clearInterval()的使用以及注意事项
    连接oracle出现的问题以及解决办法
    Oracle数据库数据显示乱码问题解决方法。
    Android4.4以上Uri转换成绝对路径的工具类
    安卓,调用相机并适配6.0后
    问题-解决
    ORACLE相关
    PL/SQL表结构/数据的导出
    springMVC笔记
  • 原文地址:https://www.cnblogs.com/DukeLv/p/9605187.html
Copyright © 2020-2023  润新知