【CF 662B】Graph Coloring

Description

现在你有一张无向图包含n个节点m条边。最初,每一条边都是蓝色或者红色。每一次你可以将一个节点连接的所有边变色(从红变蓝,蓝变红)。
找到一种步数最小的方案,使得所有边的颜色相同。

Solution

一开始看到这题,之前好像做过类似的题目,不过是在序列上的……
想了半天,啊,每个点最多只会被翻转一次:为什么呢,翻转两次会与不翻转的情况一样,翻转三次会与翻转一次的情况一样,最终翻奇数次的情况会与一次相同,翻偶数次的情况会与两次相同……所以最多只会翻转一次。
那么只要确定了一个点的翻转情况,和最终要染成的颜色,当前这个块的情况就可以确定了,很显然。
注意空间问题就好了。

Code

#include 
#include 
#include 
#include 
#define fi first
#define se second
using namespace std;
const int maxN(1e5 + 10);
typedef int i_N[maxN];
typedef pair<int, int> p_ii;
int N, M;
namespace graph{
    typedef pairint> EDGE;
    i_N P, mark;
    vector<int> adj[maxN];
    EDGE edge[maxN];

    void link(const int u, const int id){adj[u].push_back(id);}
    int adj_node(const int u, const p_ii &E){return u == E.fi? E.se : E.fi;}

    int bfs(const int sample, const int is_print){
        queue<int> bfs_node;
        memset(P, 0, sizeof(P));
        int res(0);
        for(int u = 1; u <= N; u++) if(!P[u]){
            vector<int> tmp;
            P[u] = -1;
            mark[u] = 0;
            bfs_node.push(u);
            int C(0), C1(0);
            while(!bfs_node.empty()){
                const int u(bfs_node.front()); bfs_node.pop();
                tmp.push_back(u);
                C++;
                C1 += mark[u];
                for(int i = 0; i < (int)adj[u].size(); i++){
                    const int id(adj[u][i]);
                    const int v(adj_node(u, edge[id].fi)), color(edge[id].se), t((color != sample) ^ mark[u]);
                    if(!P[v]){
                        P[v] = u;
                        mark[v] = t;
                        bfs_node.push(v);
                    }else if(mark[v] != t){
                        if(is_print) cout << -1;
                        return 2e9;
                    }
                }
            }
            res += min(C1, C - C1);
            if(C1 > C - C1) for(int i = 0; i < (int)tmp.size(); i++) mark[tmp[i]] = 1 - mark[tmp[i]];
        }
        if(is_print){
            cout << res << '\n';
            for(int u = 1; u <= N; u++) if(mark[u]) cout << u << ' ';
        }
        return res;
    }
}

int main(){

        using namespace graph;
        cin >> N >> M;
        for(int i = 0; i < M; i++){
            char ch;
            cin >> edge[i].fi.fi >> edge[i].fi.se >> ch;
            edge[i].se = ch == 'R';
            link(edge[i].fi.fi, i);
            link(edge[i].fi.se, i);
        }
    {
        using namespace graph;
        if(bfs(0, 0) < bfs(1, 0)) bfs(0, 1); else bfs(1, 1);
    }
}

你可能感兴趣的:(贪心,暴搜,CF)