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;
    }
    
  • 相关阅读:
    WinForm窗口间传值
    如何自定义标签
    oracle数据库开启的时候 是先开监听还是先开主服务,关数据库的时候呢???
    oracle 10g 安装时字符集的选择,和后边的修改
    Oracle数据库安装及配置(一)
    Win7下完全卸载Oracle 11g的步骤
    Oracle创建表空间、创建用户以及授权
    ORACLE创建表空间、创建用户、更改用户默认表空间以及授权、查看权限
    Linux 常用命令集合
    Java之JSP和Servlet基础知识
  • 原文地址:https://www.cnblogs.com/juechen/p/5255859.html
Copyright © 2011-2022 走看看