• UVA10615 Rooks 二分图的边着色


    UVA10615 Rooks

    题意:

    给你一个 (n imes n) 的矩阵,把 (n) 行和 (n) 列视作 (2n) 个点。如果矩阵中坐标 ((i,j)) 的位置是 * ,就在第 (i) 行和第 (j) 列代表的点之间连一条无向边。因此你得到了一个二分图。

    让你给每条边染色,要求每个点相邻的边中不能有重复的颜色。

    求最小的染色数,并输出一种染色方案。

    题解:

    根据 Vizing 定理,二分图的最小染色数所有点的度数的最大值。

    网上的大部分做法都是匹配做的,这里给出一种比较暴力的做法。

    这种做法是在 OI Wiki 上了解到的,以下内容直接搬运自 OI Wki 。

    从这里开始

    按照顺序在二分图中加边。

    我们在尝试加入边 ((x,y)) 的时候,我们尝试寻找对于 (x)(y) 的编号最小的尚未被使用过的颜色,假设分别为 (lx)(ly)

    如果 (lx=ly) 此时我们可以直接将这条边的颜色设置为 (lx)

    否则假设 (lx<ly) , 我们可以尝试将节点 (y) 连出去的颜色为 (lx) 的边的颜色修改为 (ly)

    修改的过程可以被近似的看成是一条从 (y) 出发,依次经过颜色为 (lx,ly,lx,ly,cdots) 的边的有限唯一增广路。

    因为增广路有限所以我们可以将增广路上所有的边反色,即原来颜色为 (lx) 的修改为 (ly) ,原来颜色为 (ly) 的修改为 (lx)

    根据二分图的性质,节点 (x) 不可能为增广路节点,否则与最小未使用颜色为 (lx) 矛盾。

    所以我们可以在增广之后直接将连接 (x)(y) 的边的颜色设为 (lx)

    总构造时间复杂度为 (O(nm))

    到这里结束

    你问我既然有了为什么还要再写一篇题解?

    因为原作者并没有给出具体的代码实现(至少 OI Wiki 上没有),我在网上也没有找到,所以就自己写了一下,希望能提供帮助。

    ps:而且我的代码跑的飞快,在 UVA 上 rank14 欸。

    AC 代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define INF 0x3f3f3f3f
    #define LLINF 0x3f3f3f3f3f3f3f3f
    #define pii pair<int,int>
    #define vi vector<int>
    #define SZ(x) (int)x.size()
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    const int MAXN = 205;
    const int MAXM = 1e4 + 5;
    char g[MAXN][MAXN]; // 原图
    struct edge { // 前向星
        int to, next, w;
    } e[MAXM * 2];
    int cnt = 1;
    int head[MAXN];
    void add_edge(int u, int v, int w = 0) {
        e[++cnt].to = v;
        e[cnt].next = head[u];
        e[cnt].w = w;
        head[u] = cnt;
    }
    int col[MAXN][MAXN]; // col[u][c]表示点u的颜色为c的边的id
    void change(int u, int L1, int L2) {
        if(!col[u][L1]) { //无法增广
            col[u][L2] = 0;
            return;
        }
        int i = col[u][L1];
        int v = e[i].to;
        change(v, L2, L1); // 继续增广
        e[i].w = e[i ^ 1].w = L2; // 修改颜色L1->L2
        col[u][L2] = i;
        col[v][L2] = i ^ 1;
    }
    void paint(int n) {
        for(int u = 1; u <= n; u++) {
            for(int i = head[u]; i; i = e[i].next) {
                if(e[i].w > 0) // 已染色
                    continue;
                int v = e[i].to;
                int Lx = INF, Ly = INF;
                for(int i = 1; i <= n; i++) { // 找最小的未使用颜色
                    if(!col[u][i])
                        Lx = min(Lx, i);
                    if(!col[v][i])
                        Ly = min(Ly, i);
                }
                if(Lx < Ly)
                    change(v, Lx, Ly);
                if(Lx > Ly)
                    change(u, Ly, Lx);
                int L = min(Lx, Ly);
                e[i].w = e[i ^ 1].w = L; // 染色
                col[u][L] = i;
                col[v][L] = i ^ 1;
            }
        }
    }
    int deg[MAXN];
    int ans[MAXN][MAXN];
    void init(int n) {
        cnt = 1; // 前向星从2开始存!
        for(int i = 0; i < n + 5; i++) {
            head[i] = deg[i] = 0;
            for(int j = 0; j < n + 5; j++)
                col[i][j] = ans[i][j] = 0;
        }
    }
    int main() {
        int t;
        scanf("%d", &t);
        while(t--) {
            int n;
            scanf("%d", &n);
            init(n * 2);
            for(int i = 0; i < n; i++) {
                getchar();
                scanf("%s", g[i]);
            }
            for(int i = 0; i < n; i++) // 建图
                for(int j = 0; j < n; j++)
                    if(g[i][j] == '*') {
                        add_edge(i + 1, j + 1 + n);
                        add_edge(j + 1 + n, i + 1);
                        deg[i + 1]++, deg[j + 1 + n]++;
                    }
            paint(n);
            for(int u = 1; u <= n; u++) // 更新答案
                for(int i = head[u]; i; i = e[i].next)
                    ans[u][e[i].to - n] = e[i].w;
            int num = 0;
            for(int i = 1; i <= 2 * n; i++) // 查找最大度数
                num = max(num, deg[i]);
            printf("%d
    ", num);
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= n; j++)
                    printf("%d ", ans[i][j]);
                printf("
    ");
            }
        }
    }
    
  • 相关阅读:
    python中线程 进程 协程
    python 部署lvs
    python中函数
    python监控cpu 硬盘 内存
    python文件操作
    python中字典
    零基础逆向工程34_Win32_08_线程控制_CONTEXT结构
    零基础逆向工程33_Win32_07_创建线程
    零基础逆向工程32_Win32_06_通用控件_VM_NOTIFY
    零基础逆向工程31_Win32_05_提取图标_修改标题
  • 原文地址:https://www.cnblogs.com/Hartley/p/13624246.html
Copyright © 2020-2023  润新知