zoukankan      html  css  js  c++  java
  • [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);
    }
    
  • 相关阅读:
    在HTML中使用css3实现雪人动画效果
    不一样的函数防抖和节流
    2020全球C++及系统软件技术大会成功落下帷幕
    详解flex布局做骰子案例
    LeetCode-环形链表|+环形链表||
    03:成绩排序
    02:奇数单增序列
    谁考了第k名
    【23.59%】【hdu 5883】The Best Path
    【30.53%】【hdu 5878】I Count Two Three
  • 原文地址:https://www.cnblogs.com/lover-fucker/p/13567961.html
Copyright © 2011-2022 走看看