zoukankan      html  css  js  c++  java
  • 【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 }
  • 相关阅读:
    PAT (Advanced Level) Practice 1055 The World's Richest (25 分) (结构体排序)
    PAT (Advanced Level) Practice 1036 Boys vs Girls (25 分)
    PAT (Advanced Level) Practice 1028 List Sorting (25 分) (自定义排序)
    PAT (Advanced Level) Practice 1035 Password (20 分)
    PAT (Advanced Level) Practice 1019 General Palindromic Number (20 分) (进制转换,回文数)
    PAT (Advanced Level) Practice 1120 Friend Numbers (20 分) (set)
    从零开始吧
    Python GUI编程(TKinter)(简易计算器)
    PAT 基础编程题目集 6-7 统计某类完全平方数 (20 分)
    PAT (Advanced Level) Practice 1152 Google Recruitment (20 分)
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8286871.html
Copyright © 2011-2022 走看看