• BZOJ 2400: Spoj 839 Optimal Marks (按位最小割)


    题面

    一个无向图,一些点有固定权值,另外的点权值由你来定.
    边的值为两点的异或值,一个无向图的值定义为所有边的值之和.

    求无向图的最小值

    分析

    每一位都互不干扰,按位处理.
    用最小割算最小值

    • 保留原图的边,容量为1
    • 如果当前点这一位是1,就从S连向当前点,容量为infty
    • 如果当前点这一位是0,就从当前点连向T,容量为infty
      那么这样一来,分在S一边就表示选,分在T一边就表示不选.如果相邻的两点在不同的集合,中间的边就必须断掉,造成1的代价,那么刚好相当于中间的边的值.

    跑一遍最小割然后从S开始搜,不搜满流的边(也就是被割开的边),加上答案即可

    • 对于在边值相等的情况下,要求点值最小的正确性如下:
      在我们的最小割中,被划分在S一边表示选,那么一条增广路径上有多条满流边的时候,我们的搜索处理方法是遇到满流边就不往下走.所以我们割的边一定最靠近S集,也就是尽量地多让剩下点被分在T集(也就是选0),这样就满足了在同等情况下尽量选0使得点值最小.
    • 另一种方法是把边值设为10000,点值设为1.那么最小边值之和就是ans/10000,在此情况下的最小点值就是ans%10000

    CODE

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    template<typename T>inline void read(T &num) {
        char ch; int flg=1;
        while((ch=getchar())<'0'||ch>'9')if(ch=='-')flg=-flg;
        for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
        num*=flg;
    }
    const int inf = 1e9;
    const int MAXN = 505;
    const int MAXM = 20005;
    int n, m, fir[MAXN], S, T, cnt;
    struct edge { int to, nxt; LL c; }e[MAXM];
    inline void add(int u, int v, LL cc, LL rc=0) {
        e[cnt] = (edge){ v, fir[u], cc }; fir[u] = cnt++;
        e[cnt] = (edge){ u, fir[v], rc }; fir[v] = cnt++;
    }
    int dis[MAXN], vis[MAXN], info[MAXN], cur, q[MAXN];
    inline bool bfs() {
        int head = 0, tail = 0;
        vis[S] = ++cur; q[tail++] = S;
        while(head < tail) {
            int u = q[head++];
            for(int i = fir[u]; ~i; i = e[i].nxt)
                if(e[i].c && vis[e[i].to] != cur)
                    vis[e[i].to] = cur, dis[e[i].to] = dis[u] + 1, q[tail++] = e[i].to;
        }
        if(vis[T] == cur) memcpy(info, fir, (T+1)<<2);
        return vis[T] == cur;
    }
    LL dfs(int u, LL Max) {
        if(u == T || !Max) return Max;
        LL flow=0, delta;
        for(int &i = info[u]; ~i; i = e[i].nxt)
            if(e[i].c && dis[e[i].to] == dis[u] + 1 && (delta=dfs(e[i].to, min(e[i].c, Max-flow)))) {
                e[i].c -= delta, e[i^1].c += delta, flow += delta;
                if(flow == Max) return flow;
            }
        return flow;
    }
    inline LL dinic() {
        memset(vis, 0, sizeof vis);
        LL flow=0, x;
        while(bfs()) {
            while((x=dfs(S, inf))) flow+=x;
        }
        return flow;
    }
    int A[MAXN], X[2005], Y[2005]; LL ans1, ans2;
    bool flg[MAXN];
    void Getans2(int u, int val) {
        if(u) ans2 += val; flg[u] = 1;
        for(int i = fir[u]; ~i; i = e[i].nxt)
            if(e[i].c && !flg[e[i].to])
                Getans2(e[i].to, val);
    }
    int main () {
        read(n); read(m); S = 0, T = n+1;
        for(int i = 1; i <= n; ++i) read(A[i]);
        for(int i = 1; i <= m; ++i) read(X[i]), read(Y[i]);
        for(int bit = 0; bit < 30; ++bit) {
            memset(fir, -1, sizeof fir); cnt = 0;
            for(int i = 1; i <= m; ++i) add(X[i], Y[i], 1, 1);
            for(int i = 1; i <= n; ++i) {
                if(A[i] < 0) continue;
                if(A[i]&(1<<bit)) add(S, i, inf);
                else add(i, T, inf);
            }
            memset(flg, 0, sizeof flg);
            ans1 += dinic() * (1<<bit);
            Getans2(S, 1<<bit);
        }
        printf("%lld
    %lld
    ", ans1, ans2);
    }
    

    Upd:Upd:不开long longlong long毁一生

  • 相关阅读:
    客户端用mstsc不能用一台设备连接终端服务器的解决办法
    [转]知识管理ABC
    Visual Studio常用小技巧[备忘]
    一套外企的数据库设计面试题
    MSDN中的图形元素和文档约定[备忘]
    设计模式概述
    ASP.Net 4.0中新增加的23项功能[转]
    Dreamweaver 8 的相关使用
    浅谈ThreadPool 线程池
    C#委托的异步调用[学习]
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039409.html
Copyright © 2020-2023  润新知