• 【SPOJ839】最优标号


    Description

    给你一张无向图G(V,E)。每个顶点都有一个标号,它是一个[0,2^31-1]内的整数。不同的顶点可能会有相同的标号。 
    对每条边(u,v),我们定义其费用cost(u,v)为u的标号与v的标号的异或值。 
    现在我们知道一些顶点的标号。你需要确定余下顶点的标号使得所有边的费用和尽可能小。

    Input

    第一行有两个整数N,M(1<=N<=500,0<=M<=3000),N是图的点数,M是图的边数。 
    接下来有M行,每行有两个整数u,v,代表一条连接u,v的边。 
    接下来有一个整数K,代表已知标号的顶点个数。接下来的K行每行有两个整数u,p,代表点u的标号是p。假定这些u不会重复。

    Output

    输出一行一个整数,即最小的费用和。

    Sample Input

    3 2 
    1 2 
    2 3 

    1 5 
    3 100

    Sample Output

    97

    Hint

    一个可能的标号方案是:点1标5,点2标4,点3标100.

    正解:最小割。

    这题真的艹。。我觉得我想太多了,还tm分0和1拆点连边。。

    考虑每个二进制位,然后题意就是要你求最小割。。所以只要把原图连好,每条边两边的点,0和1互连,然后如果当前点在当前二进制位下为1,就把它和源点连,否则和汇点连。求出最大流,就是当前二进制位1的个数。

     1 //It is made by wfj_2048~
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <cstdlib>
     6 #include <cstdio>
     7 #include <vector>
     8 #include <cmath>
     9 #include <queue>
    10 #include <stack>
    11 #include <map>
    12 #include <set>
    13 #define inf (1LL<<60)
    14 #define il inline
    15 #define RG register
    16 #define ll long long
    17 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    18 
    19 using namespace std;
    20 
    21 struct edge{ ll nt,to,flow,cap; }g[1000010];
    22 
    23 struct node{ ll u,v; }G[100010];
    24 
    25 ll head[1010],d[1010],q[1010],x[1010],y[1010],vis[1010],lk[1010],n,m,k,S,T,num,res,ans;
    26 
    27 il ll gi(){
    28     RG ll x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    29     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
    30 }
    31 
    32 il void insert(RG ll from,RG ll to,RG ll cap){ g[++num]=(edge){head[from],to,0,cap},head[from]=num; return; }
    33 
    34 il ll bfs(RG ll S,RG ll T){
    35     memset(d,0,sizeof(d)); RG ll h=0,t=1; q[t]=S,d[S]=1;
    36     while (h<t){
    37     RG ll x=q[++h];
    38     for (RG ll i=head[x];i;i=g[i].nt){
    39         RG ll v=g[i].to;
    40         if (!d[v] && g[i].cap>g[i].flow){
    41         q[++t]=v,d[v]=d[x]+1;
    42         if (v==T) return 1;
    43         }
    44     }
    45     }
    46     return 0;
    47 }
    48 
    49 il ll dfs(RG ll x,RG ll T,RG ll a){
    50     if (x==T || !a) return a; RG ll f,flow=0;
    51     for (RG ll i=head[x];i;i=g[i].nt){
    52     RG ll v=g[i].to;
    53     if (d[v]==d[x]+1 && g[i].cap>g[i].flow){
    54         f=dfs(v,T,min(a,g[i].cap-g[i].flow));
    55         if (!f){ d[v]=-1; continue; }
    56         g[i].flow+=f,g[i^1].flow-=f;
    57         flow+=f,a-=f; if (!a) return flow;
    58     }
    59     }
    60     return flow;
    61 }
    62 
    63 il ll maxflow(RG ll S,RG ll T){ RG ll flow=0; while (bfs(S,T)) flow+=dfs(S,T,inf); return flow; }
    64 
    65 il void work(){
    66     n=gi(),m=gi(),S=n+1,T=n+2;
    67     for (RG ll i=1;i<=m;++i) G[i].u=gi(),G[i].v=gi();
    68     k=gi(); for (RG ll i=1;i<=k;++i) x[i]=gi(),y[i]=gi();
    69     for (RG ll len=0,s=1;len<=30;++len,s<<=1){
    70     memset(head,0,sizeof(head)); num=1,res=0;
    71     for (RG ll i=1;i<=m;++i) insert(G[i].u,G[i].v,1),insert(G[i].v,G[i].u,1);
    72     for (RG ll i=1;i<=k;++i)
    73         if (y[i]&s) insert(S,x[i],inf),insert(x[i],S,0);
    74         else insert(x[i],T,inf),insert(T,x[i],0);
    75     ans+=maxflow(S,T)*s;
    76     }
    77     printf("%lld
    ",ans); return;
    78 }
    79 
    80 int main(){
    81     File("optimalmarks");
    82     work();
    83     return 0;
    84 }
  • 相关阅读:
    BZOJ 1911: [Apio2010]特别行动队
    BZOJ 1096: [ZJOI2007]仓库建设(动态规划+斜率优化)
    BZOJ 2243: [SDOI2011]染色(树链剖分)
    BZOJ 1834: [ZJOI2010]network 网络扩容(网络流+费用流)
    BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分)
    BZOJ 1875: [SDOI2009]HH去散步(矩阵乘法)
    BZOJ 1898: [Zjoi2004]Swamp 沼泽鳄鱼(矩阵乘法)
    BZOJ 2463: [中山市选2009]谁能赢呢?(博弈论)
    BZOJ 2879: [Noi2012]美食节
    BZOJ 1070: [SCOI2007]修车(费用流)
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6442031.html
Copyright © 2020-2023  润新知