[CSP-S模拟测试]:卡常题/b(基环树+DP)

Posted wzc521

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CSP-S模拟测试]:卡常题/b(基环树+DP)相关的知识,希望对你有一定的参考价值。

题目描述

$ρ$有一个二分连通无向图,$X$方点、$Y$方点均为$n$个(编号为$1\sim n$)。
这个二分图比较特殊,每一个$Y$方点的度为$2$,一条黑色边,一条白色边。
所有黑色边权值均为$a$,所有白色边权值均为$b$。
选择一个$X$方点,代价为连接的所有边的权值之和。
激活一个$Y$方点,需要选择至少一个与之相邻的$X$方点。
现在,$ρ$想激活每个$Y$方点,他想知道最小的总代价。
不过$ρ$很善良,他给你开了$O2$优化。
这样你就不会被卡常了。
当然,除非你真的连读入优化都不想写,或者常数真的丑死。


输入格式

第一行:三个正整数$n$、$a$、$b$。
接下来$n$行:每行两个正整数,第$i$行表示第$i-1$个$Y$方点的黑色边连接的$X$方点,白色边连接的$X$方点。


输出格式

第一行:一个整数,代表最小的总代价。


样例

样例输入:

4 2 3
1 2
3 1
1 4
2 3

样例输出:

12


数据范围与提示

$20\%$的数据:$n\leqslant 20$。
$40\%$的数据:$n\leqslant 10^3$。
另外$10\%$的数据:$a=b=1$。
另外$20\%$的数据:保证每个$X$方点连接的边颜色相同。
另外$10\%$的数据:保证原图是一个大小为$2\times n$的环。
$100\%$的数据:$n\leqslant 10^6,a,b\leqslant 100$,保证无重边。


题解

发现这张图其实就是一个基环树,所以我们可以做基环树$DP$。

首先,找到这个环,然后删掉这条边,这样就变成了一棵树了,向两个方向进行$DP$,取较小的即可。

时间复杂度:$\Theta(n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct recint nxt,to;e[2000001];
struct nodeint i,l,r;root;
int head[1000001],cnt=1;
int n,a,b;
int sam[1000001];
int dp[2][1000001][2];
bool vis[1000001];
void add(int x,int y)

	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	head[x]=cnt;

void pre_dfs(int x,int fa)

	vis[x]=1;
	for(int i=head[x];i;i=e[i].nxt)
	
		if(e[i].to==fa)continue;
		if(vis[e[i].to])root=(node)i,x,e[i].to;return;
		pre_dfs(e[i].to,x);
	

void DP0(int x,int fa)

	int sum=0;
	dp[0][x][0]=0;
	dp[0][x][1]=sam[x];
	for(int i=head[x];i;i=e[i].nxt)
	
		if(i==root.i||(i^1)==root.i||e[i].to==fa)continue;
		DP0(e[i].to,x);
		sum+=min(dp[0][e[i].to][0],dp[0][e[i].to][1]);
		dp[0][x][0]+=dp[0][e[i].to][1];
	
	dp[0][x][1]+=sum;

void DP1(int x,int fa)

	int sum=0;
	dp[1][x][0]=0;
	dp[1][x][1]=sam[x];
	for(int i=head[x];i;i=e[i].nxt)
	
		if(i==root.i||(i^1)==root.i||e[i].to==fa)continue;
		DP1(e[i].to,x);
		sum+=min(dp[1][e[i].to][0],dp[1][e[i].to][1]);
		dp[1][x][0]+=dp[1][e[i].to][1];
	
	dp[1][x][1]+=sum;

int main()

	scanf("%d%d%d",&n,&a,&b);
	for(int i=1;i<=n;i++)
	
		int x,y;
		scanf("%d%d",&x,&y);
		sam[x]+=a;sam[y]+=b;
		add(x,y);add(y,x);
	
	pre_dfs(1,0);
	DP0(root.l,0);
	DP1(root.r,0);
	cout<<min(dp[0][root.l][1],dp[1][root.r][1])<<endl;
	return 0;


rp++

以上是关于[CSP-S模拟测试]:卡常题/b(基环树+DP)的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj3037/2068]创世纪[Poi2004]SZP_树形dp_并查集_基环树

Hdu第八场 树形dp+基环树

[bzoj2878][Noi2012]迷失游乐园(基环树dp)

BZOJ 1040: [ZJOI2008]骑士(基环树dp)

bzoj 1791: [Ioi2008]Island 岛屿基环树+单调队列优化dp

[ZJOI2008] 骑士