Gym - 101615D Rainbow Roads 分析+递归标记

18 篇文章 0 订阅
这篇博客探讨了一道图论问题,题目要求在给定颜色边的树中找到所有good点,即从这些点出发到任何节点的最短路径上相邻边颜色不同。作者提出,如果某点连接的边颜色相同,则从该点出发的路径可能不合法。通过递归函数ER遍历不合规子树,并使用solve函数处理未访问节点,以寻找可能的good点。
摘要由CSDN通过智能技术生成

题意:给一棵n个结点的树,每条边都有一种颜色,要求找出所有的good点,g点定义:从这个点出发,到其他任意结点的简单路径(最短路径),相邻的两条边颜色都不同

思路:对于某个结点O,跟他相连的结点连的边是同种颜色的话,那从这个O点往这个有重复颜色的结点遍历的时候,能遍历到的点都是不合法的,因为他们以这个O点为中心有两条相邻同颜色的边,

我用ER函数遍历不合法的子树,如果在子树中又发现了相邻同色的边,那所有图中就不包含g点了

然后我继续用solve()函数处理其他没访问的点,

 

 

//#include<bits/stdc++.h>

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<set>


using namespace std;
typedef long long ll;
typedef pair<int, int> P;

const int maxn = 5e4 + 7;
const int maxd = 1e9 + 7;

const ll mod = 998244353;
const int INF = 0x7f7f7f7f;

int n;

struct node {
    int v, c;
};
vector<node> vec[maxn];
set<int> st[maxn];
set<int> er[maxn];

int vis[maxn];
bool flag = true;

void init() {
    for(int i = 1; i <= n; ++i) {
        vec[i].clear();
        st[i].clear();
        vis[i] = 0;
    }
    flag = true;
}

void print1() {
    printf("%d\n", n);
    for(int i = 1; i <= n; ++i) {
        printf("%d\n", i);
    }
}

bool ER(int id, int f, int c) {
    if(vis[id] == 1) return false;
    vis[id] = 1;
    for(auto i : vec[id]) {
        if(i.v == f) continue;
        if(i.c == c) return true;
        if(ER(i.v, id, i.c)) return true;
    }
    return false;
}
void solve(int id) {
    for(auto i : er[id]) {
        for(auto j : vec[id]) {
            if(j.c == i) {
                if(ER(j.v, id, i)) {
                    printf("0\n");
                    flag = false;
                    return;
                }
            }
        }
    }
    vis[id] = 2;
    for(auto i : vec[id]) {
        if(!vis[i.v]) {
            solve(i.v);
        }
    }
}
void work() {
    vector<int> ans;
    for(int i = 1; i <= n; ++i) {
        if(vis[i] == 2) ans.push_back(i);
    }
    printf("%d\n", ans.size());
    for(auto i : ans) {
        printf("%d\n", i);
    }
}
int main() {
    scanf("%d", &n);
    init();
    for(int i = 1; i < n; ++i) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        vec[a].push_back(node{b, c});
        vec[b].push_back(node{a, c});

        if(st[a].count(c)) er[a].insert(c);
        else st[a].insert(c);
        if(st[b].count(c)) er[b].insert(c);
        else st[b].insert(c);
    }
    int x = -1;
    for(int i = 1; i <= n; ++i) {
        if(er[i].size()) {
            x = i;
            break;
        }
    }
//    cout << x << " =++= ==++ " << endl;
    if(x == -1) {
        print1();
    }
    else {
        solve(x);
        if(flag) {
            work();
        }
    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值