洛谷 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