zoukankan      html  css  js  c++  java
  • 十七个中毒的英国人

    题目

    利内罗女士准备来到意大利进行修行。
    意大利由 n 个城市和 m 条道路构成,道路是双向的。
    到达第 i 个城市时,她可以取得该城市的全部信仰,并获得 ai 点能力提升,但因为在一个城市可以
    取得的信仰有限,多次到达同一个城市不会多次提升能力。
    意大利对能力也有很严的要求,对于第 i 条道路,只有能力大于等于 bi 的人才能经过。
    利内罗女士准备乘坐飞机去往意大利,飞机可以降落在任意城市(即可以在任意城市开始修行),她
    想知道自己的能力最多可以成长为多少。
    她提出了 Q 次询问,表示当自己初始能力为 qi 时,能力最多可以成长为多少。

    Input

    第一行三个整数 n, m, Q。接下来一行 n 个非负整数,a1 到 an。
    接下来 m 行,每行三个正整数,ui, vi, bi,表示城市 ui 和城市 vi 之间有一条道路。
    最后 Q 行,每行一个非负整数 qi。

    output

    Q 行,每行一个整数表示答案。

    Notes
    对于所有数据,满足 n, Q ≤ 105, m ≤ 2 ∗ 105, ai ≤ 104, qi, bi ≤ 109
    Task1[20%]

    n ≤ 5 , m ≤ 10 , Q =1

    Task2[30%]
    n ≤ 50 , m ≤ 100 , Q ≤ 5

    Task3[40%]

    n ≤ 100 , m ≤ 200 , Q ≤5

    Task4[50%]
    n ≤ 300 , m ≤ 600 , Q ≤ 100

    Task5[60%]

    n ≤ 1000 , m ≤ 2000 , Q ≤ 10

    Task6[100%]
    无特殊限制
    Subtask1[10pts]
    n ≤ 1000 , m = n − 1 , Q ≤ 1000,图保证联通
    Subtask2[10pts]
    m = n − 1,图保证联通0


    思路(超时算法)

    爆内存,爆时间,纯粹的爆搜。定路,定点,储蓄信仰,判断够不够。不行后返回;最后输出结果。


    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int inf=0x3f3f3f3f;
    int a[100000],n,m,bi,q,ui[200000],vi[200000],b[10000][10000],ans,qi,sum=0;
    bool road[10000][10000],place[100000];
    void dfs(int x)
    {
        if(place[x]==false)
        {
            ans=ans+a[x];
            place[x]=true;
        }
        if(ans>sum)
        sum=ans;
        for(int i=1;i<=n;i++)
        {
            if(i==x)
            continue;
            else if(road[x][i]==true&&ans>=b[x][i])
            {
                road[x][i]=false;
                road[i][x]=false;
                dfs(i);
            }
        }
        ans=ans-a[x];
    }
    int main()
    {
        freopen("cemetery.in.txt","r",stdin);
        freopen("cemetery.out.txt","w",stdout);
        cin>>n>>m>>q;
        for(int i=1;i<=n;i++)
        cin>>a[i];
        for(int i=1;i<=m;i++)
        {
            cin>>ui[i]>>vi[i]>>bi;
            b[ui[i]][vi[i]]=bi;
            b[vi[i]][ui[i]]=bi;
        }
        for( int i=1;i<=q;i++)
        {
            cin>>qi;
            ans=qi;
            for(int j=1;j<=n;j++)
            {
                memset(road,false,sizeof(road));
                memset(place,false,sizeof(place));
                for(int i1=1;i1<=m;i1++)
                {
                    road[ui[i1]][vi[i1]]=true;
                    road[vi[i1]][ui[i1]]=true;
                }
                
                dfs(j);
            }
            cout<<sum<<endl;        
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    思路(正解)

    n ≤ 5 , m ≤ 10 , Q = 1
    直接搜索.

    n ≤ 100 , m ≤ 200 , Q ≤ 5
    枚举起点,每次去一个能去的城市,看最后能去多少个城市
    时间复杂度 O(qn2m).

    n ≤ 300 , m ≤ 600 , Q ≤ 100
    堆优化上个算法
    时间复杂度 O(qmn log n)

    n ≤ 1000 , m ≤ 2000 , Q ≤ 1000
    先对于每个点处理出当初始能力值为多少时的答案
    排一下序,对于每个询问二分出最优解
    时间复杂度 O(nm log n + q log n)

    n ≤ 1000 , m = n − 1 , Q ≤ 1000,图保证联通
    首先,对于一个特定的 q,从每个点延伸出去的答案要么包含,要么不相交.

    从每个点开始延伸,如果之前已经延伸过就直接合并
    可以用左偏树维护
    时间复杂度 O(qn log n).

    m = n − 1,图保证联通
    考虑合并
    一定是这条边的要求比原连通块中所有边的要求都要大
    所以可以把边按照要求的大小排序,从小到大来合并连通块
    用并查集维护即可
    时间复杂度 O((n + m + q)log n).

    无特殊限制
    首先,最后的答案一定是一个连通块
    考虑哪些连通块可能成为答案
    首先,每个点都可能是答案
    其次,我们发现,如果能经过一条边,那么和它相邻并且要求更低的边也能经过
    所以和 Subtask2 其实是一样的
    用并查集维护
    时间复杂度 O((n + m + q)log n).

    题解就不发了,有点多。解释得很清楚了。(有些东西本人也还没有弄懂

    那么,这就结束了吧!

  • 相关阅读:
    希腊字母大全
    SQL 等值连接(内连接)、自然连接(Out join,Left join,Right join)的区别
    JDK11 JAVA11下载安装与快速配置环境变量教程
    “由爱故生忧,由爱故生怖。若离于爱者,无忧亦无怖”
    How to use special characters in XML?
    Crow’s Foot Notation
    How do I unmute my Lenovo laptop?
    Nginx学习笔记--001-Nginx快速搭建
    Nginx 相关介绍
    java使用httpclient封装post请求和get的请求
  • 原文地址:https://www.cnblogs.com/abcdhh/p/11182097.html
Copyright © 2011-2022 走看看