01染色 codeforces663C Graph Coloring

传送门:点击打开链接

题意:一个无向图中,每条边可能是0或者1。有一种对节点u的操作,操作时把节点u连接的所有边的权值0变1,1变0.现在要把所有边的权值边成相等的,问最少的操作步数,并打印方案。

思路:如果确定最后边的颜色了,并对所有的连通块中,确定了一个节点的颜色,那么整个连通块的操作节点就是唯一确定的了。

打印方案比较麻烦,,慢慢debug。。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int MX = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
struct Ans {
    bool ok;
    vector<int>s;
    bool operator<(const Ans &P)const {
        if(ok == P.ok) return s.size() < P.s.size();
        return ok > P.ok;
    }
};
int n, m;
struct Edge {
    int v, nxt, z;
} E[MX << 2];
int Head[MX], erear;
void edge_init() {
    erear = 0;
    memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v, int z) {
    E[erear].v = v;
    E[erear].z = z;
    E[erear].nxt = Head[u];
    Head[u] = erear++;
}
int col[MX], vis[MX];
Ans deal(int x, int u, int c) {
    Ans ret; ret.ok = true;
    vector<int> p;
    queue<int> Q;
    Q.push(u); col[u] = c; vis[u] = 1;
    p.push_back(u);
    while(!Q.empty()) {
        u = Q.front(); Q.pop();
        if(col[u]) ret.s.push_back(u);
        for(int i = Head[u]; ~i; i = E[i].nxt) {
            int v = E[i].v;
            if(vis[v] && (col[u]^col[v]^E[i].z) != x) {
                ret.ok = false; break;
            }
            if(!vis[v]) {
                col[v] = E[i].z ^ col[u] ^ x;
                vis[v] = 1; Q.push(v);
                p.push_back(v);
            }
        }
    }
    if(c == 0) {
        for(int i = 0; i < p.size(); i++) {
            vis[p[i]] = 0;
        }
    }
    return ret;
}
Ans solve(int x) {
    Ans ret, temp;
    memset(vis, 0, sizeof(vis));
    for(int i = 1; i <= n; i++) {
        if(vis[i]) continue;
        temp = min(deal(x, i, 1), deal(x, i, 0));
        if(!temp.ok) {
            ret.ok = false;
            return ret;
        }
        for(int j = 0; j < temp.s.size(); j++) {
            ret.s.push_back(temp.s[j]);
        }
    }
    ret.ok = true;
    return ret;
}
int main() {
    edge_init(); //FIN;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i++) {
        int u, v; char op[10];
        scanf("%d%d%s", &u, &v, op);
        int z = op[0] == 'R' ? 1 : 0;
        edge_add(u, v, z);
        edge_add(v, u, z);
    }
    Ans ans = min(solve(0), solve(1));
    if(!ans.ok) printf("-1\n");
    else {
        int sz = ans.s.size();
        printf("%d\n", sz);
        for(int i = 0; i < sz; i++) {
            printf("%d%c", ans.s[i], i == sz - 1 ? '\n' : ' ');
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值