[D2T3]w

题目描述

有一棵 n 个节点的树,每条边长度为 1,颜色为黑或白。

可以执行若干次如下操作:选择一条简单路径,反转路径上所有边的颜色。

对于某些边,要求在操作结束时为某一种颜色。

给定每条边的初始颜色,求最小操作数,以及满足操作数最小时,最小的操作路径长度和。

输入格式

第一行,一个正整数 n。

接下来 n-1 行,每行四个整数 a, b, c, d:

• 树中有一条边连接 a 和 b。

• c = 0, 1 表示初始颜色为白色、黑色。

• d = 0, 1, 2 表示最终要求为白色、要求为黑色、没有要求。

输出格式

输出一行,两个整数,表示最小操作数、操作数最小时的最小路径长度和。

样例

样例输入1
5
2 1 1 0
1 3 0 1
2 4 1 2
5 2 1 1
样例输出1
1 2
样例解释1
操作路径 {2, 1, 3}。
样例输入2
3
1 3 1 2
2 1 0 0
样例输出2
0 0
样例输入3
6
1 3 0 1
1 2 0 2
2 4 1 0
4 5 1 0
5 6 0 2
样例输出3
1 4

数据范围与提示

对于100%的数据,保证给出的图为一棵树,有 n ∈ [1,1e5 ],a, b ∈ [1, n],c ∈ {0, 1},d ∈ {0, 1, 2}。
在这里插入图片描述

题解

d = 2 输0,得了1分。
对于第三个数据,是一个链,我们选择贪心,每个连续的需要翻转的搞一下,
如果两个连续的块中间夹着一堆可翻可不翻的合并一下即可。
很显然 我们每个边肯定只会翻转一次,那么每个边只有翻与不翻两种情况,这为我们dp提供了条件,翻过的边我们构成了一个边集,那么反转次数的答案这个集合就是奇数度的点个数/2。
我们令(dp[u][1/0])表示点u的儿子,是否翻转它到父亲结点这个边,得到的奇数度的点的个数最小值,以及边的个数,即路径长度和。
(w_1)表示u的儿子v,它转移的集合中有一条翻转到u的最小代价
(w_2)则表示没有这样的翻转边的最小代价
易得
(w_1 = min(w_1 + dp[v][0],w_2 + dp[v][1]))
(w_2 = min(w_1 + dp[v][1],w_2 + dp[v][0]))
初始化(w_1)为极大值,(w_2)清零
如果u的头顶必须要翻转
(dp[u][0] = inf)
(dp[u][1] = min(mp(w_1.first,w_1.second + 1),mp(w_2.first + 1,w_2.second + 1)))
分别代表u翻转向上延伸,奇数点不变,路径长度+1 和u独立翻转出去,奇数点与路径长均+1

如果u的头顶一定不需要翻转
(dp[u][1] = inf)
(dp[u][0] = min(mp(w_1.first + 1,w_1.second),w_2))
表示u成为奇数点,或没有操作
不是很好描述(原谅我的口胡)
放代码吧

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<ctime>
#define mp(a,b) make_pair(a,b)
#define fi first
#define pii pair<int,int>
#define se second
#define LL long long
#define N 100005
#define inf 0x3f3f3f3f
using namespace std;
int n;
pii dp[N][2];
vector<pii>G[N];
pii operator + (pii a,pii b){
	return mp(a.fi + b.fi,a.se + b.se);
}
void dfs(int u,int fa,int op){
	pii w1,w2,rw1,rw2;
	w1.fi = w1.se = inf;
	w2.fi = w2.se = 0;
	for (int i = 0;i < G[u].size();i ++){
		int v = G[u][i].fi,flag = G[u][i].se;
		if (v == fa)
			continue;
		dfs(v,u,flag);
		rw1 = min(w1 + dp[v][0],w2 + dp[v][1]);
		rw2 = min(w1 + dp[v][1],w2 + dp[v][0]);
		w1 = rw1,w2 = rw2;
	}
	if (op == 1 || op == 2)
		dp[u][1] = min(mp(w1.fi,w1.se + 1),mp(w2.fi + 1,w2.se + 1));
	else 
		dp[u][1] = mp(inf,inf);
	if (op == 0 || op == 2)
		dp[u][0] = min(w2,mp(w1.fi + 1,w1.se));
	else 
		dp[u][0] = mp(inf,inf);
}
int main(){
	scanf ("%d",&n);
	for (int i = 1;i < n;i ++){
		int a,b,c,d,op;
		scanf ("%d%d%d%d",&a,&b,&c,&d);
		if (d == 2)
			op = 2;
		else if (c != d)
			op = 1;
		else 
			op = 0;
		G[a].push_back(mp(b,op));
		G[b].push_back(mp(a,op));
	}
	dfs(1,0,2);
	printf("%d %d
",dp[1][0].fi / 2,dp[1][0].se);
}
原文地址:https://www.cnblogs.com/lover-fucker/p/13567961.html