zoukankan      html  css  js  c++  java
  • BZOJ1562: [NOI2009]变换序列(二分图 匈牙利)

    Description

    Input

    Output

    Sample Input

    5
    1 1 2 2 1

    Sample Output

    1 2 4 0 3

    HINT

    30%的数据中N≤50;
    60%的数据中N≤500;
    100%的数据中N≤10000。

    Source

    这题是二分图应该不难看出来。

    对于原序列中的一个点,对应两个可匹配的点。

    关键是怎么保证字典序最小

    如果是暴力删边+匈牙利的话是$O(n^3)$的。

    这里有两种解决方法:

    1.强制让$x$号点连向字典序小的点,对失配的点重新匹配

    2.将所有边按照字典序排序,优先选择最小的。

     同时在匈牙利的时候从最大的往最小的枚举

        这实际上利用了匈牙利“抢” 的思想。

        如之前的已经匹配过,那么字典序小的会抢字典序大的匹配。同时又因为每次选的是字典序最小的。因此答案可以保证是最优的。

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    const int INF = 1e9 + 10, MAXN = 1e5 + 10;
    using namespace std;
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N;
    int a[MAXN];
    int match[MAXN], vis[MAXN], cur;
    vector<int> v[MAXN];
    void AddEdge(int x, int y) {
        v[x].push_back(y); 
        v[y].push_back(x);
    }
    bool Argue(int x) {
        for(int i = 0; i < v[x].size(); i++) {
            int to = v[x][i];
            if(vis[to] == cur) continue;
            vis[to] = cur; 
            if(match[to] == -1 || Argue(match[to])) {
                match[to] = x;
                return true;
            }
        }
        return false;
    }
    void Hug() {
        int ans = 0;
        for(int i = N - 1; i >= 0; i--) {
            cur++;
            if(!Argue(i)) {printf("No Answer"); exit(0);}
        }    
        for(int i = 0; i < N; i++) match[match[i + N]] = i;
        for(int i = 0; i < N; i++) printf("%d ", match[i]);
    }
    main() { 
    #ifdef WIN32
        freopen("a.in", "r", stdin);
        freopen("a.out", "w", stdout);
    #endif
        memset(match, -1, sizeof(match));
        N = read();
        for(int i = 0; i < N; i++) {
            int x = read();
            AddEdge(i, (i + x) % N + N);
            AddEdge(i, (i - x + N) % N + N);
        }
        for(int i = 0; i < N << 1; i++) sort(v[i].begin(), v[i].end());
        Hug();
    }
  • 相关阅读:
    关闭防火墙,仍然无法访问80端口 centos
    apache添加虚拟主机(windows下)
    PHP实现文件下载
    chmod 777 修改权限之后,文件夹颜色变绿:解决方案
    element ui table(表格)点击一行展开
    vue中eventbus 多次触发的问题
    console.log、toString方法与js判断变量类型
    另一个维度:cocos-2d VS vue
    浏览器内置的base64方法
    H5网页涂鸦canvas
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/9271851.html
Copyright © 2011-2022 走看看