zoukankan      html  css  js  c++  java
  • noip模拟赛 传球接力

    【问题描述】
    n 个小朋友在玩传球。 小朋友们用 1 n 的正整数编号。 每个小朋友有一个固定的传球
    对象,第 i 个小朋友在接到球后会将球传给第 ai个小朋友, 并且第 i 个小朋友与第 ai个小朋
    友之间的距离为 di
    一次传球接力是这样进行的:由一个小朋友发球,将球传给他的传球对象,之后接到球
    的小朋友再将球传给自己的传球对象,如此传球若干次后停止。 期间,包括发球者在内,每
    个小朋友至多只能拿到球一次。 一次传球接力的总距离是每次传球的距离的总和。
    小朋友们想进行一次总距离最长的传球接力,现在需要你帮助他们求出满足上述要求的
    传球接力的最长总距离。
    【输入】
    输入的第 1 行包含 1 个整数 n
    接下来的 n 行,第 i 行包含两个整数 ai di,意义如题目中所述, 两个数间用一个空格
    隔开。
    【输出】
    输出包含 1 个数, 表示传球接力总距离的最大值。
    【输入输出样例 1

    pass.in pass.out
    5
    2 1
    3 2
    4 1
    2 3
    3 3
    7


    见选手目录下的 pass / pass1.in pass / pass1.out
    【输入输出样例 1 说明】
    由第 5 个小朋友发球, 传给第 3 个小朋友,再传给第 4 个小朋友,总距离为 3+1+3=7
    【数据规模与约定】
    对于 50%的数据, n≤1,000
    对于 100%的数据, n≤500,0001≤ai≤naii1≤di≤10,000

    分析:对图的特征一定要搞清楚,比如n个点n-1条边就是树,n个点n条边就是树套环,每个点出度为1就是很多链和环的结合体.为了走的最远,肯定要从入度为0的点出发,走到环上,顺着环走一遍.每次都模拟这样走一遍效率不高,因为一个环会被多次使用,所以可以先把环的长度给预处理出来,再把每个入度为0的点到环上的距离利用树形dp给算出来,因为最后不能回到自身嘛,枚举一下断点就可以了.

          因为图可能不是连通的,会有多个环,所以要把所有的点都给处理到位.

    暴力50分:

    #include <map>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 500010;
    
    int n, head[maxn], maxx,to[maxn], nextt[maxn], w[maxn], tot = 1, ans;
    bool vis[1010];
    long long sum;
    
    void add(int x, int y, int z)
    {
        w[tot] = z;
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    void dfs(int x, int d)
    {
        vis[x] = 1;
        ans = max(ans, d);
        for (int i = head[x]; i; i = nextt[i])
        {
            int v = to[i];
            if (!vis[v])
                dfs(v, d + w[i]);
        }
    }
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
        {
            int a, d;
            scanf("%d%d", &a, &d);
            add(i, a, d);
        }for (int i = 1; i <= n; i++)
            {
                dfs(i, 0);
                memset(vis, 0, sizeof(vis));
            }
            printf("%d
    ", ans);return 0;
    }

    正解:

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 500010;
    ll n, a[maxn], d[maxn], du[maxn], f[maxn], sum = 0, ans, pre[maxn], cnt, p[maxn];
    bool vis[maxn];
    
    int main()
    {
        scanf("%lld", &n);
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld%lld", &a[i], &d[i]);
            du[a[i]]++;
        }
        queue <ll> q;
        for (int i = 1; i <= n; i++)
            if (!du[i])
                q.push(i);
        while (!q.empty())
        {
            ll u = q.front();
            q.pop();
            ll v = a[u];
            f[v] = max(f[v], f[u] + d[u]);
            if (--du[v] == 0)
                q.push(v);
        }
        for (int i = 1; i <= n; i++)
            if (du[i] && !vis[i])
            {
                ll k = i;
                sum = 0;
                do
                {
                    vis[k] = 1;
                    p[++cnt] = k;
                    pre[a[k]] = d[k];
                    sum += d[k];
                    k = a[k];
                } while (k != i);
                for (int j = 1; j <= cnt; j++)
                    ans = max(ans, sum + f[p[j]] - pre[p[j]]);
            }
        printf("%lld
    ",ans);
    
        return 0;
    }
  • 相关阅读:
    Windows Server 2003下ASP.NET无法识别IE11的解决方法
    SQL Server2005中使用XML-数据类型、查询与修改
    连接SQLServer时提示“但是在登录前的握手期间发生错误。 (provider: SSL Provider, error: 0
    无法将类型为 excel.applicationclass 的 com 强制转换为接口类型 的解决方法。
    C# WinForm使用Aspose.Cells.dll 导出导入Excel/Doc 完整实例教程
    技巧 获取电脑硬件信息 -转发
    浏览器无需下载插件 解决网页长截图的小技巧 -转发
    note 9 列表、时间复杂度、排序
    note 8 字符串
    note 7 递归函数
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7743106.html
Copyright © 2011-2022 走看看