zoukankan      html  css  js  c++  java
  • BZOJ 3774 最优选择 (最小割+二分图)

    题面传送门

    题目大意:给你一个网格图,每个格子都有$a_{ij}$的代价和$b_{ij}$的回报,对于格子$ij$,想获得$b_{ij}$的回报,要么付出$a_{ij}$的代价,要么$ij$周围四联通的格子都付出代价,求最大的回报-代价

    好神的一道题,%%%jr

    想获得$b_{ij}$的回报,要么付出$a_{ij}$的代价,要么$ij$周围四联通的格子都付出代价

    所以把棋盘像国际象棋一样黑白交叉染色,原图就变成了一个类似于二分图的东西

    每个格子都拆成$2$个点

    对于白格子,源点$S$向$W1$连流量为$a_{ij}$的边,$W1$向$W2$连流量为$b_{ij}$的边,$W2$向白格子周围四个黑格子的$B2$连流量为$inf$的边

    对于黑格子,$B2$向汇点$T$连流量为$a_{ij}$的边,$B1$向$B2$连流量为$b_{ij}$的边,周围四个白格子的$W1$向$B1$连流量为$inf$的边

    然后跑最大流,答案就是总回报-最大流

    为什么要这么建边?我们可以对割进行分析

    如果一个白格子的代价边$a_{ij}$被割掉了,说明这个格子带来的回报$geq$代价,被归到了$T$集合里,此时流量$=$代价,统计答案时会加上回报$-$代价

    如果一个白格子的代价边$a_{ij}$没被割掉,说明这个格子带来的回报$<$代价,被归到了$S$集合里,此时流量$=$回报,统计答案时会把这部分回报去掉

    黑格子也是同理

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #define N1 5010
      5 #define M1 30010
      6 #define L1 55
      7 using namespace std;
      8 const int inf=0x3f3f3f3f;
      9 
     10 int gint()
     11 {
     12     int ret=0,fh=1;char c=getchar();
     13     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     14     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     15     return ret*fh;
     16 }
     17 struct Edge{
     18 int to[M1<<1],nxt[M1<<1],flow[M1<<1],head[N1],cte;
     19 void ae(int u,int v,int f)
     20 {
     21     cte++; to[cte]=v; nxt[cte]=head[u];
     22     head[u]=cte; flow[cte]=f; 
     23 }
     24 }e;
     25 
     26 int dep[N1],que[M1],cur[N1],n,m,hd,tl,S,T;
     27 int bfs()
     28 {
     29     int x,j,v;
     30     memset(dep,-1,sizeof(dep)); memcpy(cur,e.head,sizeof(cur));
     31     hd=1,tl=0; que[++tl]=S; dep[S]=0;
     32     while(hd<=tl)
     33     {
     34         x=que[hd++];
     35         for(j=e.head[x];j;j=e.nxt[j])
     36         {
     37             v=e.to[j];
     38             if( dep[v]==-1 && e.flow[j]>0 )
     39             {
     40                 dep[v]=dep[x]+1;
     41                 que[++tl]=v;
     42             }
     43         }
     44     }
     45     return dep[T]!=-1;
     46 }
     47 int dfs(int x,int limit)
     48 {
     49     int j,v,flow,ans=0;
     50     if(!limit||x==T) return limit;
     51     for(j=cur[x];j;j=e.nxt[j])
     52     {
     53         v=e.to[j]; cur[x]=j;
     54         if( dep[v]==dep[x]+1 && (flow=dfs(v,min(limit,e.flow[j]))) )
     55         {
     56             e.flow[j]-=flow; limit-=flow;
     57             e.flow[j^1]+=flow; ans+=flow;
     58             if(!limit) break;
     59         }
     60     }
     61     return ans;
     62 }
     63 int Dinic()
     64 {
     65     int mxflow=0,j,v,ans=0;
     66     while(bfs())
     67         mxflow+=dfs(S,inf);
     68     return mxflow;
     69 }
     70 
     71 int xx[4]={-1,0,1,0},yy[4]={0,1,0,-1};
     72 int a[L1][L1],b[L1][L1],id[L1][L1];
     73 inline int check(int x,int y){return (x<1||y<1||x>n||y>m)?0:1;}
     74 
     75 int main()
     76 {
     77     scanf("%d%d",&n,&m);
     78     int i,j,x,y,k,tot=n*m,sum=0; e.cte=1; S=0; T=tot+tot+1;
     79     for(i=1;i<=n;i++) for(j=1;j<=m;j++) a[i][j]=gint();// sum+=v[i][j];
     80     for(i=1;i<=n;i++) for(j=1;j<=m;j++) b[i][j]=gint(), id[i][j]=(i-1)*m+j, sum+=b[i][j];
     81     for(i=1;i<=n;i++) for(j=1;j<=m;j++)
     82     {
     83         x=id[i][j]; 
     84         if((i+j)&1){
     85             e.ae(S,x,a[i][j]); e.ae(x,S,0);
     86             e.ae(x,x+tot,b[i][j]); e.ae(x+tot,x,0);
     87             for(k=0;k<4;k++)
     88             {
     89                 if(!check(i+xx[k],j+yy[k])) continue;
     90                 y=id[i+xx[k]][j+yy[k]];
     91                 e.ae(x+tot,y+tot,inf); e.ae(y+tot,x+tot,0);
     92             }
     93         }else{
     94             e.ae(x+tot,T,a[i][j]); e.ae(T,x+tot,0);
     95             e.ae(x,x+tot,b[i][j]); e.ae(x+tot,x,0);
     96             for(k=0;k<4;k++)
     97             {
     98                 if(!check(i+xx[k],j+yy[k])) continue;
     99                 y=id[i+xx[k]][j+yy[k]];
    100                 e.ae(y,x,inf); e.ae(x,y,0);
    101             }
    102         }
    103     }
    104     printf("%d
    ",sum-Dinic());
    105     return 0;
    106 }
  • 相关阅读:
    反转链表 --剑指offer
    链表的倒数第K个节点
    打印1到最大的n位数----java实现
    Permutations java实现
    Generate Parentheses java实现
    Binary Tree Level Order Traversal java实现
    hadoop中日志聚集问题
    PIG的配置
    hadoop2.20.0集群安装教程
    Map/Reduce之间的Partitioner接口
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10349034.html
Copyright © 2011-2022 走看看