zoukankan      html  css  js  c++  java
  • OPTM-Optimal Marks-SPOJ839最小割

    You are given an undirected graph G(V, E). Each vertex has a mark which is an integer from the range [0..231 – 1]. Different vertexes may have the same mark.

    For an edge (u, v), we define Cost(u, v) = mark[u] xor mark[v].

    Now we know the marks of some certain nodes. You have to determine the marks of other nodes so that the total cost of edges is as small as possible.

    Input

    The first line of the input data contains integer T (1 ≤ T ≤ 10) - the number of testcases. Then the descriptions of T testcases follow.

    First line of each testcase contains 2 integers N and M (0 < N <= 500, 0 <= M <= 3000). N is the number of vertexes and M is the number of edges. Then M lines describing edges follow, each of them contains two integers u, v representing an edge connecting u and v.

    Then an integer K, representing the number of nodes whose mark is known. The next K lines contain 2 integers u and p each, meaning that node u has a mark p. It’s guaranteed that nodes won’t duplicate in this part.

    Output

    For each testcase you should print N lines integer the output. The Kth line contains an integer number representing the mark of node K. If there are several solutions, you have to output the one which minimize the sum of marks. If there are several solutions, just output any of them.

    Example

    Input:
    1
    3 2
    1 2
    2 3
    2
    1 5
    3 100

    Output:
    5
    4
    100

    在Amber的最小割论文上看到的一道题。
    这里写图片描述
    这里写图片描述
    考虑到是异或运算求最小cost之和,由于对于二进制,各个位之间是互不影响的,所以可以将问题转会为每个二进制位的求解,然后求和即可。对于每个二进制位,要么为0,要么为1, 就想到将整个图切割成两个点
    集,即对于每个点,都只有两种取值,可以看成是要将点集划分成两类。在这种分类思想的指导下,重新考察操作的意义:对于边的两个端点,若它们同类则边权无值;若它们异类则边权有值1。
    建一源点S,汇点T
    对于已经标号过的点:
    1. 对于位为1的点建边 < S, V, INF, 0>
    2. 对于位为0的点建边 < V, T, INF, 0>
    对于所有的原边
    建成流量为1的双向边< u, v, 1, 1>
    这样求得最小割,即为当前位的最优解。
    这样建边,求最小割时,保证了割边都是原边,求完后,所有与S相连的点可以标号为1, 所有与T相连的边标号为0, 那么这些割边即为相邻点异类的边,同时保证了他们的和最小。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    
    const int MaxN = 550;
    
    const int MaxM = 3100;
    
    typedef struct node
    {
        int u,v;
    }Point;
    
    typedef struct Node
    {
        int v,next,cap;
    }edge ;
    
    Point a[MaxM];
    
    edge e[MaxM*10];
    
    int mark[MaxN],vis[MaxN],Ans[MaxN];
    
    int H[MaxN];
    
    int n,m,k,s,t,top;
    
    void AddEdge(int u,int v,int w1,int w2)
    {
        e[top].v = v; e[top].cap = w1;
    
        e[top].next = H[u]; H[u]= top++;
    
        e[top].v = u; e[top].cap = w2;
    
        e[top].next = H[v]; H[v] = top++;
    }
    
    bool BFS()
    {
        memset(vis,0,sizeof(vis));
    
        queue<int>Q;
    
        vis[s] = 1;
    
        Q.push(s);
    
        while(!Q.empty())
        {
            int  u =Q.front();
    
            Q.pop();
    
            for(int i=H[u];~i;i=e[i].next)
            {
                if(e[i].cap>0&&!vis[e[i].v])
                {
                    vis[e[i].v] = vis[u]+1;
    
                    Q.push(e[i].v);
                }
            }
        }
    
        return vis[t];
    }
    
    int DFS(int u,int cap)
    {
        if(u==t)
        {
            return cap;
        }
    
        int ans = 0;
    
        for(int i=H[u];~i;i=e[i].next)
        {
            if(e[i].cap>0&&vis[e[i].v]==vis[u]+1)
            {
                int ant = DFS(e[i].v,min(e[i].cap,cap));
    
                ans += ant;
    
                cap -= ant;
    
                e[i].cap-=ant;
    
                e[i^1].cap+=ant;
    
                if(cap==0)
                {
                    break;
                }
            }
        }
    
        return ans;
    }
    
    void Dinic()
    {
        while(BFS())
        {
            DFS(s,INF);
        }
    }
    
    void dfs(int u,int bite)
    {
        vis[u] = 1;
    
        Ans[u]+=bite;
    
        for(int i = H[u];i!=-1;i=e[i].next)//和S相连都为1
        {
            if(e[i].cap>0&&!vis[e[i].v])
            {
                dfs(e[i].v,bite);
            }
        }
    }
    void Solve()
    {
        int bite=1;
    
        memset(Ans,0,sizeof(Ans));
    
        while(1)
        {
            top = 0;
    
            memset(H,-1,sizeof(H));
    
            for(int i=1;i<=m;i++)
            {
                AddEdge(a[i].u,a[i].v,1,1);
            }
    
            bool flag=false;
    
            for(int i=1;i<=n;i++) //以每一位求一次最小割
            {
                if(mark[i]!=-1)
                {
                    if(mark[i]>=1)
                    {
                        flag=true;
                    }
                    if(mark[i]%2)
                    {
                        AddEdge(s,i,INF,0);
                    }
                    else
                    {
                        AddEdge(i,t,INF,0);
                    }
    
                    mark[i]>>=1;
                }
            }
    
            if(!flag)//都为零的时候算法结束
            {
                break;
            }
    
            Dinic();
    
            memset(vis,0,sizeof(vis));
    
            dfs(s,bite);
    
            bite<<=1;
        }
    
        for(int i=1;i<=n;i++)
        {
            if(i!=1) printf(" ");
    
            printf("%d",Ans[i]);
        }
        puts("");
    }
    
    int main()
    {
        int T;
    
        scanf("%d",&T);
    
        int u,v,w;
    
        while(T--)
        {
            scanf("%d %d",&n,&m); 
    
            s=0,t=n+1;
    
            for(int i=1;i<=m;i++) scanf("%d %d",&a[i].u,&a[i].v);
    
            scanf("%d",&k);
    
            memset(mark,-1,sizeof(mark));
    
            for(int i=1;i<=k;i++)
            {
                scanf("%d %d",&u,&w);
    
                mark[u] = w; 
            }
    
            Solve();
        }
        return 0;
    }
    
  • 相关阅读:
    深度分析:SpringBoot异常捕获与封装处理,看完你学会了吗?
    去年去阿里面试,面试官居然问我Java类和对象,我是这样回答的!
    面试官:小伙子,你给我详细说一下线程的状态有哪些吧?
    新鲜出炉!JAVA线程池精华篇深度讲解,看完你还怕面试被问到吗?
    面试官:小伙子,你给我讲一下java类加载机制和内存模型吧
    深度分析:面试90%被问到的多线程、创建线程、线程状态、线程安全,一次性帮你全搞定!
    close与shutdown
    select模型(二 改进服务端)
    select模型(一 改进客户端)
    5种IO模型
  • 原文地址:https://www.cnblogs.com/juechen/p/5255859.html
Copyright © 2011-2022 走看看