• P1453 城市环路


    题目背景

    一座城市,往往会被人们划分为几个区域,例如住宅区、商业区、工业区等等。B市就被分为了以下的两个区域——城市中心和城市郊区。在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市中心。

    题目描述

    整个城市可以看做一个N个点,N条边的单圈图(保证图连通),唯一的环便是绕城的环路。保证环上任意两点有且只有2条路径互通。图中的其它部分皆隶属城市郊区。

    现在,有一位名叫Jim的同学想在B市开店,但是任意一条边的2个点不能同时开店,每个点都有一定的人流量Pi,在该点开店的利润就等于该店的人流量Pi×K(K≤10000),K的值将给出。

    Jim想尽量多的赚取利润,请问他应该在哪些地方开店?

    输入输出格式

    输入格式:

    第一行一个整数N 代表城市中点的个数。城市中的N个点由0~N-1编号。

    第二行N个正整数,表示每个点的人流量Pi(Pi≤10000)。

    下面N行,每行2个整数A,B,表示A,B建有一条双向路。

    最后一行一个实数K。

    输出格式:

    一个实数M,(保留1位小数),代表开店的最大利润。

    输入输出样例

    输入样例#1: 复制
    4
    1 2 1 5
    0 1
    0 2
    1 2
    1 3
    2
    
    输出样例#1: 复制
    12.0

    说明

    【数据范围】

    对于20%的数据,N≤100.

    对于另外20%的数据,环上的点不超过2000个

    对于50%的数据 N≤50000.

    对于100%的数据 N≤100000.

    //一道上午的时候不知道哪错了发了讨论然后放弃了的题。
    //感谢@sqairy 大佬   一语道破我的错误所在
     
    //楼下都用的dfs找环,当时没想出用dfs做来,所以在输入的时候处理的环 
    //因为如果一条边的端点已经全部出现的话,我们把这条边加进去,就构成了一个环,
    //所以开一个flag[]标记,标记这个点有没有输入过,
    //如果 flag[u]&&flag[v],那么这肯定是一个环上的一条边,然后让A=u,B=v,
    //并且我们不把这条边加进图里,这样就构成了一棵树 
    //从A,B做两次树形DP,找最大值。 和没有上司的舞会那道题一样 
    //还有就是要取max(dp[A][0],dp[B][0]),
    //为什么是不选A和B的情况的最大值:
    //因为我们如果是在选A或B的情况中取最大值,我们不能保证A(B)选了,但是B(A)没选
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    const int N=1e6+5;
    
    int n,A,B;
    double K;
    int p[N];
    int head[N],num_edge;
    bool flag[N];
    double dp[N][2];
    struct Edge
    {
        int v,nxt;
    }edge[N<<1];
    
    int read()
    {
        char c=getchar();int num=0;
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num;
    }
    
    void add_edge(int u,int v)
    {
        edge[++num_edge].v=v;
        edge[num_edge].nxt=head[u];
        head[u]=num_edge;
    }
    
    void dfs(int u,int fa)
    {
        dp[u][1]=p[u],dp[u][0]=0;
        for(int i=head[u],v;i;i=edge[i].nxt)
        {
            v=edge[i].v;
            if(v==fa)
                continue;
            dfs(v,u);
            dp[u][0]+=max(dp[v][0],dp[v][1]);    //这个点不选,加上它的儿子选或不选的最大值 
            dp[u][1]+=dp[v][0];    //这个点选,它的儿子们不能选 
        }
    }
    
    int main()
    { 
        n=read();
        for(int i=0;i<n;++i)
            p[i]=read();
        bool ok=0;    //标记找没找到环 
        for(int i=1,u,v;i<=n;++i)
        {
            u=read(),v=read();
            if(!ok&&flag[u]&&flag[v])    //一条边的两个端点都出现过,那么着肯定是一个环上的边 
            {
                ok=1;    //找到环了 
                A=u,B=v;    //记录两个端点 
                continue;    //不加这条边 
            }
            flag[u]=flag[v]=1;        //标记两个端点已经出现过 
            add_edge(u,v);    //加边 
            add_edge(v,u);
        }
        scanf("%lf",&K);
        dfs(A,A);    //从A跑DFS 
        double ans=dp[A][0];
        dfs(B,B);    //从B跑DFS 
        ans=max(ans,dp[B][0]);
        printf("%.1lf",ans*K);
        return 0;
    }
  • 相关阅读:
    Eclipse集成Tomcat:6个常见的”how to”问题
    linux环境变量配置
    (原创)JS点击事件——Uncaught TypeError: Cannot set property 'onclick' of null
    [ JS 进阶 ] 闭包,作用域链,垃圾回收,内存泄露
    webstorm安装后的一些设置技巧:
    前端工程师的知识体系
    Git常用命令及软件推荐
    Vue.js双向绑定的实现原理
    GET和POST面试知识点
    CSS 巧用 :before和:after
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8477000.html
Copyright © 2020-2023  润新知