洛谷 P1453 城市环路

原题链接

\(n\)个点\(n\)条边,题目保证连通,所以原图是个无向的基环树,考虑基环树\(dp\)

这题可以用树形\(dp\) + 环形\(dp\)实现。

首先把环给找出来,然后对于环上的每个点\(u\),做以\(u\)为根节点的树形\(dp\)(类似没有上司的舞会)。

然后做环形\(dp\),需要注意两点:

1、转移的顺序是\(dfs\)

2、因为是环,起点和终点的状态不能冲突,所以需要枚举起点的状态,求两遍环形\(dp\)取最大值

#include<bits/stdc++.h>
using namespace std;

#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;

const int INF = 0X3f3f3f3f, N = 1e5 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);

int n;
double k;

int p[N];

int head[N], idx;

struct EGDE {
	int to, next;
} eg[N << 1];

void add(int x, int y) {
	eg[idx].to = y;
	eg[idx].next = head[x];
	head[x] = idx++;
}

int d[N], st[N]; // u不在环上: st[u] == true

void find_c() {
	queue<int> q;
	rep(i, 0, n - 1) if (d[i] == 1) q.push(i);
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		st[u] = true;
		for (int i = head[u]; ~i; i = eg[i].next) {
			int to = eg[i].to;
			if (st[to]) continue;
			if (--d[to] == 1) q.push(to);
		}
	}
}

int f[N][2];

void DP_1(int u, int fa) {
	f[u][1] = p[u];
	for (int i = head[u]; ~i; i = eg[i].next) {
		int to = eg[i].to;
		if (to == fa || st[to] == false) continue;
		DP_1(to, u);
		f[u][0] += max(f[to][1], f[to][0]);
		f[u][1] += f[to][0];
	}
}

int Start, cnt, dfs_id[N];

void dfs(int u, int fa) {
	dfs_id[++cnt] = u;
	for (int i = head[u]; ~i; i = eg[i].next) {
		int to = eg[i].to;
		if (to == fa || st[to] || to == Start) continue;
		dfs(to, u);
		break;
	}
}

int dp[N][2], ans;

void DP_2() {
	memset(dp, 0xcf, sizeof dp);
	dp[1][1] = f[dfs_id[1]][1];
	rep(i, 2, cnt) {
		dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]) + f[dfs_id[i]][0];
		dp[i][1] = dp[i - 1][0] + f[dfs_id[i]][1];
	}
	ans = dp[cnt][0];

	memset(dp, 0xcf, sizeof dp);
	dp[1][0] = f[dfs_id[1]][0];
	rep(i, 2, cnt) {
		dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]) + f[dfs_id[i]][0];
		dp[i][1] = dp[i - 1][0] + f[dfs_id[i]][1];
	}
	ans = max(ans, max(dp[cnt][0], dp[cnt][1]));
}

void work() {
	memset(head, -1, sizeof head);
	scanf("%d", &n);
	rep(i, 0, n - 1) scanf("%d", p + i);
	rep(i, 0, n - 1) {
		int x, y;
		scanf("%d%d", &x, &y);
		add(x, y);
		add(y, x);
		d[x]++, d[y]++;
	}
	scanf("%lf", &k);

	//找环
	find_c();
	
	Start = -1;
	rep(i, 0, n - 1) {
		if (!st[i]) {
			DP_1(i, -1);
			if (Start == -1) Start = i;
		}
	}
	
	dfs(Start, -1);
	DP_2();

	printf("%.1lf\n", ans * k);
}

signed main() {
	int test = 1;
	//	cin >> test;

	while (test--) {
		work();
	}

	return 0;
}
posted @ 2022-08-03 23:08  xhy666  阅读(34)  评论(0)    收藏  举报