• Optimal Marks SPOJ


    题意:给一张无向图,每个点有其点权,边(i,j)的cost是(val_i XOR val_j).现在只给出K个点的权值,求如何安排其余的点,使总花费最小.
    分析:题目保证权值不超过32位整型,按每一位k上的值(0 or 1),将点分为两个集合X和Y,X中为1的点,Y为0的点.如果X中的点到Y中的边有边,表示这一点对对结果将产生贡献.用最小的费用将对象划分成两个集合,问题转化为求最小割的问题.
    建图:建源点s和汇点t.从s向X中的点建容量为正无穷的边;从Y中的点向t建容量为正无穷的边,对于相邻的点对(ij)分别向对方建一条容量为1的边,跑一遍最大流.之后还需要知道有哪些点该位被修改成了1.从源点出发的点,若不在最小割中,就说明实际选择了该点,将其该位变成1.从源点进行一次dfs即可.

    #include<iostream>
    #include<cstring>
    #include<stdio.h>
    #include<algorithm>
    #include<string>
    #include<cmath>
    #include<set>
    #include<map>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    typedef int LL;
    const int MAXN=1010;//点数的最大值
    const int MAXM=400010;//边数的最大值
    #define captype int
    
    struct SAP_MaxFlow{
        struct edgesE{
            int from,to,next;
            captype cap;
        }edges[MAXM];
        int eid,head[MAXN];
        int gap[MAXN];
        int dis[MAXN];
        int cur[MAXN];
        int pre[MAXN];
    
        void init(){
            eid=0;
            memset(head,-1,sizeof(head));
        }
        void AddEdge(int u,int v,captype c,captype rc=0){
            edges[eid].from = u;
            edges[eid].to=v; edges[eid].next=head[u];
            edges[eid].cap=c;  head[u]=eid++;
            edges[eid].from = v;
            edges[eid].to=u; edges[eid].next=head[v];
            edges[eid].cap=rc; head[v]=eid++;
        }
        captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
            memset(gap,0,sizeof(gap));
            memset(dis,0,sizeof(dis));
            memcpy(cur,head,sizeof(head));
            pre[sNode] = -1;
            gap[0]=n;
            captype ans=0;
            int u=sNode;
            while(dis[sNode]<n){
                if(u==eNode){
                    captype Min=INF ;
                    int inser;
                    for(int i=pre[u]; i!=-1; i=pre[edges[i^1].to])
                    if(Min>edges[i].cap){
                        Min=edges[i].cap;
                        inser=i;
                    }
                    for(int i=pre[u]; i!=-1; i=pre[edges[i^1].to]){
                        edges[i].cap-=Min;
                        edges[i^1].cap+=Min;
                    }
                    ans+=Min;
                    u=edges[inser^1].to;
                    continue;
                }
                bool flag = false;
                int v;
                for(int i=cur[u]; i!=-1; i=edges[i].next){
                    v=edges[i].to;
                    if(edges[i].cap>0 && dis[u]==dis[v]+1){
                        flag=true;
                        cur[u]=pre[v]=i;
                        break;
                    }
                }
                if(flag){
                    u=v;
                    continue;
                }
                int Mind= n;
                for(int i=head[u]; i!=-1; i=edges[i].next)
                if(edges[i].cap>0 && Mind>dis[edges[i].to]){
                    Mind=dis[edges[i].to];
                    cur[u]=i;
                }
                gap[dis[u]]--;
                if(gap[dis[u]]==0) return ans;
                dis[u]=Mind+1;
                gap[dis[u]]++;
                if(u!=sNode) u=edges[pre[u]^1].to;  //退一条边
            }
            return ans;
        }
    }F;
    
    int G[505][505];
    int mark[505];
    int N,M,K,s,t;
    int vis[MAXN];
    int id[505];
    void build(int dig)
    {
        F.init();
        s=0,t = N+1;
        for(int i=1;i<=K;++i){
            int u = id[i];
            if((1<<dig)&mark[u]){           //s->1
                F.AddEdge(s,u,INF);
            }
            else{                           //0->t
                F.AddEdge(u,t,INF);
            }
        }
        for(int i=1;i<=N;++i){
            for(int j=i+1;j<=N;++j){
                if(G[i][j]){
                    F.AddEdge(i,j,1);
                    F.AddEdge(j,i,1);
                }
            }
        }
    }
    
    void dfs(int u,int dig)
    {
        vis[u] = 1;
        mark[u] |= (1<<dig);
        for(int i=F.head[u];~i;i=F.edges[i].next){
            int v = F.edges[i].to;
            if(!vis[v] && F.edges[i].cap){
                dfs(v,dig);
            }
        }
    }
    
    int main()
    {
    	#ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        int T;  scanf("%d",&T);
        int u,v,tmp;
        while(T--){
            scanf("%d %d",&N, &M);
            memset(G,0,sizeof(G));
            memset(mark,0,sizeof(mark));
            for(int i=1;i<=M;++i){
                scanf("%d %d",&u, &v);
                G[u][v] = G[v][u] =1;
            }
            scanf("%d",&K);
            for(int i=1;i<=K;++i){
                scanf("%d",&u);
                scanf("%d",&mark[u]);
                id[i] = u;
            }
            for(int i=0;i<=31;++i){
                build(i);
                F.maxFlow_sap(s,t,t+1);
                memset(vis,0,sizeof(vis));
                dfs(s,i);
            }
            for(int i=1;i<=N;++i){
                printf("%d
    ",mark[i]);
            }
        }
        return 0;
    }
    
    为了更好的明天
  • 相关阅读:
    汇编入门——使用DOSBox写一个HelloWorld以及相关软件安装
    HCNA-链路聚合(手工模式)
    逆向工程-真码保存在系统文件破解QQ游戏对对碰助手
    逆向工程-获得IPsearch的注册码
    遇见tongtong的思绪
    rhel7--06-预习--磁盘分区命令
    rhel7--05--第三章管道符与重定向符
    rhel7--01--安装
    虚拟机Centos8,没有网络,wired图标消失
    kali是靶体,内置工具可就地取材------网络安全法要天天供奉
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9687857.html
Copyright © 2020-2023  润新知