zoukankan      html  css  js  c++  java
  • 城市环路「树形DP」

    题目描述

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

    现在,有一位名叫 Jim 的同学想在 B 市开店,但是任意一条边的 (2) 个点不能同时开店,每个点都有一定的人流量,第 (i) 个点的人流量是 (p_i)​,在该点开店的利润就等于 (p_i×k),其中 (k) 是一个常数。

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

    输入格式

    第一行一个整数 (n),代表城市中点的个数。城市中的 (n) 个点由 (0 sim n-1) 编号。

    第二行有 (n) 个整数,第 ((i + 1)) 个整数表示第 iii 个点的人流量 (p_i)

    接下来 (n) 行,每行有两个整数 (u, v),代表存在一条连接 (u)(v) 的道路。

    最后一行有一个实数,代表常数 (k)

    输出格式

    输出一行一个实数代表答案,结果保留一位小数。

    输入输出样例

    输入 #1

    4
    1 2 1 5
    0 1
    0 2
    1 2
    1 3
    2
    

    输出 #1

    12.0
    

    思路分析

    • 这明显是一棵基环树,然而我并不会对其进行处理
    • 用于解决基环树问题的有一个很常用又简单的方法,就是断环法,即断开一条边,然后从断开的这一条边的端点分别跑一遍,最后取最优值
    • 用并查集判环就行了,这样方便直接断边(忽略不加)
    • 明白这个这题应该问题就不大了,记得用子节点来更新父结点

    (Code)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define R register
    #define N 100010
    using namespace std;
    inline int read(){
    	int x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,p[N],f[N][2],fa[N],head[N],s,t,ans;
    double K;
    struct edge{
    	int to,next;
    }e[N<<1];
    int len;
    void addedge(int u,int v){
    	e[++len].to = v;
    	e[len].next = head[u];
    	head[u] = len;
    }
    void dfs(int u,int prt){
    	f[u][0] = 0,f[u][1] = p[u];
    	for(R int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(v==prt)continue;
    		dfs(v,u);
    		f[u][0] += max(f[v][0],f[v][1]);
    		f[u][1] += f[v][0];
    	}
    }
    int find(int x){
    	return fa[x]==x ? x: fa[x]=find(fa[x]);
    }
    int main(){
    	n = read();
    	for(R int i = 1;i <= n;i++)p[i] = read();
    	for(R int i = 1;i <= n;i++)fa[i] = i;
    	for(R int i = 1;i <= n;i++){
    		int x = read()+1,y = read()+1;
    		if(find(x)==find(y)){s = x,t = y;continue;}
    		else fa[find(x)] = find(y);
    		addedge(x,y),addedge(y,x);
    	}
    	scanf("%lf",&K);
    	dfs(s,0);
    	ans = f[s][0];
    	dfs(t,0);
    	ans = max(ans,f[t][0]);
    	printf("%.1f",ans*K);
    	return 0;
    }
    
  • 相关阅读:
    操作系统__kali(1)基本操作指令,以及常用工具
    Log4net入门(回滚日志文件篇)
    Log4net入门(日志文件篇)
    Log4net入门(控制台篇)
    openwrt控制GPIO
    openwrt DTS介绍
    openwrt bin文件解析
    STM32(三十)蓝牙通信
    openwrt的led configuration
    uci文件生成脚本函数说明
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13761531.html
Copyright © 2011-2022 走看看