P1453 城市环路


基环树上的没有上司我舞会。我们需要把环断开。可以任取环上一对点,将该边断开,就形成了一棵树。然后从这边的两个端点(设为S,T)分别进行树形DP。DP状态设置和上司我舞会一样,然后在f[0][T]和f[0][S]中取max,这样可以保证两点不会同时选到。

可以用并查集在建图过程中建图找环。
这个的实质就是在环上最后的一条边要加入的时候不让它加入

#include
#define rep(i,j,k) for(int i(j);i<=k;++i)
#define drp(i,j,k) for(int i(j);i>=k;--i)
#define repg(x) for(int i(G.head[x]);i;i=G.next[i])
#define bug cout<<"~~~~~~~~~~~~~"<<'\n';
using std::cin;
using std::cout;
typedef long long lxl;
template
inline T  max( T a, T b) {
	return a > b ? a : b;
}
template
inline T  min( T a, T b) {
	return a < b ? a : b;
}
const int N = 1e5 + 79;
struct graph {
	int head[N], tot, next[N << 1], ver[N << 1];
	inline void add(int a, int b) {
		ver[++tot] = b;
		next[tot] = head[a];
		head[a] = tot;
	}
} G;
int n, p[N], S, T, ans;
namespace bingchaji {
	int fa[N];
	int f[2][N];
	inline int find(int x) {
		while(x != fa[x]) x = fa[x] = fa[fa[x]];
		return x;
	}

	inline void DP(int x, int pre) {
		f[0][x] = 0;
		f[1][x] = p[x];
		repg(x) {
			int y(G.ver[i]);
			if(y == pre)continue;
			DP(y, x);
			f[0][x] += max(f[1][y], f[0][y]);
			f[1][x] += f[0][y];
		}
	}

	int main() {
		int x, y;

		rep(i, 1, n) {
			fa[i] = i;
		}

		rep(i, 1, n) {
			cin >> x >> y;
			++x;
			++y;
			if(find(x) == find(y)) {
				S = x;
				T = y;
				continue;
			}
			fa[find(x)] = find(y);
			G.add(x, y);
			G.add(y, x);
		}
		DP(S, 0);
		ans = max(ans, f[0][S]);
		DP(T, 0);
		ans = max(ans, f[0][T]);
		double k;
		cin >> k;
		cout << std::fixed << std::setprecision(1) << ans*k << '\n';
		return 0;
	}
}

int main() {
	cin >> n;
	rep(i, 1, n) {
		cin >> p[i];
	}
	bingchaji::main();
	return 0;
}

相关