zoukankan      html  css  js  c++  java
  • [bzoj2400]Optimal Marks

    首先肯定每一位单独考虑,对于每一位,源点连向该位点权为0的节点inf的边,点权为1的节点连向汇点inf的边,每一条无向边拆成两条流量为1的有向边,跑最小割。

    考虑一组割,一定将原图划分成源点和汇点两部分,那么左半部分都选0,右半部分都选1,那么它的代价就是割的代价,即要求最小割。

    为了让点的值最小,相当于要让汇点集合的点数尽量少,那么直接从汇点搜一遍,将所有能走到的节点记为1,其他记为0即可。

    还有一种做法比较神奇,将两点之间的边权增加为10000(需要大于总点数即可),然后再让源点向每一个点再连一条1的边,最小割一定是在10000最少的前提下(即图的点权最小)让源点割掉的点最少(源点割掉的每一条边都是到汇点集合的点)。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 505
     4 #define inf 0x3f3f3f3f
     5 struct ji{
     6     int nex,to,len;
     7 }e[N*20],edge[N*20];
     8 queue<int>q;
     9 int E,EE,n,m,x,y,a[N],w[N],head[N],work[N],d[N];
    10 long long ans1,ans2;
    11 void add(int x,int y,int z){
    12     edge[E].nex=head[x];
    13     edge[E].to=y;
    14     edge[E].len=z;
    15     head[x]=E++;
    16     if (E&1)add(y,x,0);
    17 }
    18 bool bfs(){
    19     memset(d,-1,sizeof(d));
    20     q.push(0);
    21     d[0]=0;
    22     while (!q.empty()){
    23         int k=q.front();
    24         q.pop();
    25         for(int i=head[k];i!=-1;i=edge[i].nex)
    26             if ((edge[i].len)&&(d[edge[i].to]<0)){
    27                 d[edge[i].to]=d[k]+1;
    28                 q.push(edge[i].to);
    29             }
    30     }
    31     return d[n+1]>=0;
    32 }
    33 int dfs(int k,int s){
    34     if (k>n)return s;
    35     int p;
    36     for(int &i=work[k];i!=-1;i=edge[i].nex)
    37         if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){
    38             p=dfs(edge[i].to,min(s,edge[i].len));
    39             if (p){
    40                 edge[i].len-=p;
    41                 edge[i^1].len+=p;
    42                 return p;
    43             }
    44         }
    45     return 0;
    46 }
    47 int dinic(){
    48     int k,ans=0;
    49     while (bfs()){
    50         memcpy(work,head,sizeof(head));
    51         while (k=dfs(0,inf))ans+=k;
    52     }
    53     return ans;
    54 }
    55 int main(){
    56     scanf("%d%d",&n,&m);
    57     memset(head,-1,sizeof(head));
    58     for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    59     for(int i=1;i<=m;i++){
    60         scanf("%d%d",&x,&y);
    61         add(x,y,10000);
    62         add(y,x,10000);
    63     }
    64     for(int i=1;i<=n;i++)
    65         if (w[i]<0)add(0,i,1);
    66         else ans2+=w[i];
    67     EE=E;
    68     memcpy(a,head,sizeof(a));
    69     memcpy(e,edge,sizeof(e));
    70     for(int i=0;i<31;i++){
    71         E=EE;
    72         memcpy(head,a,sizeof(a));
    73         memcpy(edge,e,sizeof(e));
    74         for(int j=1;j<=n;j++)
    75             if (w[j]>=0)
    76                 if (w[j]&(1<<i))add(j,n+1,inf);
    77                 else add(0,j,inf); 
    78         int p=dinic();
    79         ans1+=p/10000*(1LL<<i);
    80         ans2+=p%10000*(1LL<<i);
    81     }
    82     printf("%lld\n%lld",ans1,ans2);
    83 }
    View Code
  • 相关阅读:
    shell脚本之redis自动安装
    脚本系列之jdk安装脚本
    Hibernate查询方式汇总(一)
    LDA数学八卦笔记(一)Gamma函数
    软工实践寒假作业(1/2)
    结对项目-四则运算 “软件”之升级版
    第三次作业:个人项目-小学四则运算 “软件”之初版
    分布式版本控制系统Git的安装与使用
    第一次作业
    分布式版本控制系统Git的安装与使用
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/11249672.html
Copyright © 2011-2022 走看看