• 【bzoj2400】Spoj 839 Optimal Marks 按位最大流


    Spoj 839 Optimal Marks

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 908  Solved: 347
    [Submit][Status][Discuss]

    Description

    定义无向图中的一条边的值为:这条边连接的两个点的值的异或值。
    定义一个无向图的值为:这个无向图所有边的值的和。
    给你一个有n个结点m条边的无向图。其中的一些点的值是给定的,而其余的点的值由你决定(但要求均为非负数),使得这个无向图的值最小。在无向图的值最小的前提下,使得无向图中所有点的值的和最小。
     

    Input

    第一行两个数n,m,表示图的点数和边数
    接下来n行,每行一个数,按编号给出每个点的值(若为负数则表示这个点的值由你决定,值的绝对值大小不超过10^9)。
    接下来m行,每行二个数a,b,表示编号为a与b的两点间连一条边。(保证无重边与自环。)
     

    Output

        第一行,一个数,表示无向图的值。
        第二行,一个数,表示无向图中所有点的值的和。
     

    Sample Input

    3 2
    2
    -1
    0
    1 2
    2 3

    Sample Output

    2
    2

    HINT

    数据约定

      n<=500,m<=2000

     

    样例解释

        2结点的值定为0即可。

    因为是xor,可以从按位的思考

    这种两个答案的,二维偏序差不多,一般会想到费用流,

    但是这里可以是图的权值扩大到点权和到达不了的状态,即不由点权和影响。

    这样/mx 为图的权值,%mx为点的权和。

    然后考虑建图,设S为0集合,T为1集合,所以只需要考虑边两个端点一个选S,一个选T这样才会产生值。

    看限制了,如果当前这位有值,那么就按这个赋值,如果是1,那么S-i为inf,i-T为1;

    这样的,边的话,就是10000的边。

    具体看代码。

    每次的最大流的意义不同,代表1<<i。

      1 #include<cstring>
      2 #include<cmath>
      3 #include<iostream>
      4 #include<cstdio>
      5 #include<algorithm>
      6 #include<queue>
      7 
      8 #define inf 1000000007
      9 #define ll long long
     10 #define N 507
     11 #define M 20007
     12 using namespace std;
     13 inline int read()
     14 {
     15     int x=0,f=1;char ch=getchar();
     16     while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
     17     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
     18     return x*f;
     19 }
     20 
     21 int n,m,S,T;
     22 int num[N];
     23 int cnt,hed[N],nxt[M],rea[M],val[M],cur[N];
     24 int dis[N];
     25 ll ans1,ans2;
     26 struct Node
     27 {
     28     int    x,y;
     29 }a[M];
     30 
     31 void add(int u,int v,int w)
     32 {
     33     nxt[++cnt]=hed[u];
     34     hed[u]=cnt;
     35     rea[cnt]=v;
     36     val[cnt]=w;
     37 }
     38 void add_two_edge(int u,int v,int w)
     39 {
     40     add(u,v,w);
     41     add(v,u,0);
     42 }
     43 void build(int x)
     44 {
     45     memset(hed,-1,sizeof(hed)),cnt=1;
     46     for (int i=1;i<=n;i++)
     47         if (num[i]<0) add_two_edge(i,T,1);
     48         else
     49         {
     50             if (num[i]&(1<<x))add_two_edge(S,i,inf),add_two_edge(i,T,1);
     51             else add_two_edge(i,T,inf);
     52         }
     53     for (int i=1;i<=m;i++)
     54         add_two_edge(a[i].x,a[i].y,10000),
     55         add_two_edge(a[i].y,a[i].x,10000);
     56 }
     57 bool bfs()
     58 {
     59     for (int i=S;i<=T;i++)dis[i]=-1;
     60     dis[S]=0;
     61     queue<int>q;q.push(S);
     62     while(!q.empty())
     63     {
     64         int u=q.front();q.pop();
     65         for (int i=hed[u];i!=-1;i=nxt[i])
     66         {
     67             int v=rea[i],fee=val[i];
     68             if (dis[v]!=-1||!fee)continue;
     69             dis[v]=dis[u]+1;
     70             if (v==T)return 1;
     71             q.push(v);
     72         }
     73     }
     74     return 0;
     75 }
     76 ll dfs(int u,int MX)
     77 {
     78     ll res=0;
     79     if (MX==0||u==T)return MX;
     80     for (int i=cur[u];i!=-1;i=nxt[i])
     81     {
     82         int v=rea[i],fee=val[i];
     83         if (dis[v]!=dis[u]+1)continue;
     84         int x=dfs(v,min(MX,fee));
     85         cur[u]=i,res+=x,MX-=x;
     86         val[i]-=x,val[i^1]+=x;
     87         if (MX==0) break;
     88     }
     89     if (!res)dis[u]=-1;
     90     return res;
     91 }
     92 ll dinic()
     93 {
     94     ll res=0;
     95     while(bfs())
     96     {
     97         for (int i=S;i<=T;i++)cur[i]=hed[i];
     98         res+=dfs(0,inf);
     99     }
    100     return res;
    101 }
    102 int main()
    103 {
    104     n=read(),m=read(),S=0,T=n+1;int mx=-1;
    105     for (int i=1;i<=n;i++)
    106     {
    107         num[i]=read();
    108         mx=max(mx,num[i]);
    109     }
    110     for (int i=1;i<=m;i++)a[i].x=read(),a[i].y=read();
    111     for (int i=0;(1<<i)<=mx;i++)
    112     {
    113         build(i);
    114         ll res=dinic();
    115         ans1+=(res/10000)*(ll)(1<<i);
    116         ans2+=(res%10000)*(ll)(1<<i);
    117     }
    118     printf("%lld
    %lld
    ",ans1,ans2);
    119 }
  • 相关阅读:
    记:关于反演
    记:关于费马平方和定理的证明
    【2021集训队互测一】愚蠢的在线法官 题解
    CSP/NOIP2021 赛前集训
    20220108 省选组 总结
    Atcoder比赛总结
    Python读取execl数据写入到mysql
    大家都可以拖动的web小方块——Node.js摸石头系列之七
    创建一个Mybatis工程
    Spring整合Mybatis
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8286871.html
Copyright © 2020-2023  润新知