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;
    }
    
  • 相关阅读:
    存储过程之基本语法
    SQL存储过程概念剖析
    SQL2005之SA提权总结
    关于存储过程
    Java开发环境之------MyEclipse快捷键和排除错误第一选择ctrl+1(***重点***:ctrl+1,快速修复---有点像vs中的快速using
    MyEclipse Servers视窗出现“Could not create the view: An unexpected exception was thrown”错误解决办法
    艾泰路由器端口映射怎么设置
    常用端口
    jdbc注册驱动 class.forName()
    MyEclipse不能自动编译解决办法总结
  • 原文地址:https://www.cnblogs.com/juechen/p/5255859.html
Copyright © 2011-2022 走看看