zoukankan      html  css  js  c++  java
  • 洛谷 P1453 城市环路 ( 基环树树形dp )

    题目链接###

    题目背景###

    一座城市,往往会被人们划分为几个区域,例如住宅区、商业区、工业区等等。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

    题解###

    基环树树形dp 好高级的样子
    其实并不难。。。

    显然,题目给的图是一个有且仅有一个环的无向联通图
    那么断掉环上的一边就会变成一颗树

    考虑树形dp

    假如断掉的边为 A-B

    f[i][0/1] 0表示不选当前点,1表示选
    以A为根做一遍树形dp,但我们并不知道B有没有选
    所以干脆不选A, 再以B为根做一遍
    ans = max(f[A][0], f[B][0]) * k

    Code###

    #include<bits/stdc++.h>
    #define LL long long
    #define RG register
    using namespace std;
    
    inline int gi() {
        int f = 1, s = 0;
        char c = getchar();
        while (c != '-' && (c < '0' || c > '9')) c = getchar();
        if (c == '-') f = -1, c = getchar();
        while (c >= '0' && c <= '9') s = s*10+c-'0', c = getchar();
        return f == 1 ? s : -s;
    }
    const int N = 100010;
    struct node {
    	int to, next;
    }g[N<<1];
    int last[N], gl;
    
    inline void add(int x, int y) {
    	g[++gl] = (node) {y, last[x]};
    	last[x] = gl;
    	return ;
    }
    
    int A, B, w[N];
    bool vis[N], ok;
    void find(int u, int fa) {
    	vis[u] = 1;
    	for (int i = last[u]; i; i = g[i].next) {
    		int v = g[i].to;
    		if (vis[v]) {
    			A = u, B = v;
    			ok = 1;
    			return ;
    		}
    		find(v, u);
    		if (ok) return ;
    	}
    	return ;
    }
    
    int f[N][3];
    inline void dfs(int u, int fa) {
    	vis[u] = 1;
    	f[u][0] = 0; f[u][1] = w[u];
    	for (int i = last[u]; i; i = g[i].next) {
    		int v = g[i].to;
    		if (v == fa || vis[v]) continue;
    		dfs(v, u);
    		f[u][0] += max(f[v][1], f[v][0]);
    		f[u][1] += f[v][0];
    	}
    	return ;
    }
    
    int main() {
        //freopen(".in", "r", stdin);
        //freopen(".out", "w", stdout);
    	int n = gi();
    	for (int i = 1; i <= n; i++) w[i] = gi();
    	for (int i = 1; i <= n; i++) {
    		int u = gi()+1, v = gi()+1;
    		add(u, v), add(v, u);
    	}
    	double k;
    	scanf("%lf", &k);
    	find(1, 0);
    	memset(vis, 0, sizeof(vis));
    	dfs(A, A);
    	int ans = f[A][0];
    	memset(vis, 0, sizeof(vis));
    	dfs(B, B);
    	ans = max(ans, f[B][0]);
    	printf("%.1lf
    ", ans*k);
        return 0;
    }
    
  • 相关阅读:
    动态规划——划分
    动态规划——子序列
    动态规划——棋盘
    广搜——变换类
    广搜——连通块
    贪心
    数学——大整数问题
    图论——生成树
    动态规划——面积覆盖
    广搜——路径寻找
  • 原文地址:https://www.cnblogs.com/zzy2005/p/9846542.html
Copyright © 2011-2022 走看看