zoukankan      html  css  js  c++  java
  • bzoj2132: 圈地计划(无比强大的最小割)

    2132: 圈地计划

    题目:传送门

    简要题意:

      给出一个矩阵,一共n*m个点,并给出三个收益矩阵。A矩阵表示这个点建A的可取收益,B矩阵表示这个点建B的可取收益,C矩阵表示如果相邻(有且仅有一条公共边)的点和自己所建的建筑不一样,则可获得C[i][j]的收益,如果相邻的有k个点和自己不一样,则收益为k*C[i][j]。求最大收益。

     

    题解:

       日常一模最小割%%%ORZ

       本蒟蒻其实也看出是最小割什么的,但是怎么割啊。。。

       可能有人会和我有一样的疑惑:

       按照正常的割法建图:st到x连A收益,x到ed连B收益,两两之间再连C收益

       连完之后就蒙B了...割出来的是什么鬼???

       这时我们会发现,这样子连的话负权边根本没有体现啊???

      %题解啊啊啊:

       正解其实是需要进行黑白染色的(原因后面讲)

       染完色之后:st到黑点连A收益,黑点到ed连B收益;白点反之,然后相邻的不同颜色的格子相互连边(其实就是每个点还要连出去上下左右的点,因为染色了啊)

       这样之后用sum-最小割就OK。

       那染色是什么鬼:

       正确答案并不一定是相邻的点颜色都不一样,那么染色的目的就不是保证收益最大。

       但是染完色之后再跑最小割我们可以发现:

       如果某相邻两点异色的收益不如同色的收益,那么这条路径上关于相邻异色的收益肯定会被割掉

       如果异色收益更优,那割掉的肯定是一个A收益加一个B收益

       那么肯定是要最小割啊~

    代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<cmath>
      5 #include<algorithm>
      6 #define qread(x) x=read()
      7 using namespace std;
      8 inline int read()
      9 {
     10     int f=1,x=0;char ch;
     11     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     12     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
     13     return f*x;
     14 }
     15 struct node
     16 {
     17     int x,y,c,next,other;
     18 }a[1110000];int len,last[110000];
     19 int n,m,st,ed,head,tail;
     20 void ins(int x,int y,int c)
     21 {
     22     int k1,k2;
     23     k1=++len;
     24     a[len].x=x;a[len].y=y;a[len].c=c;
     25     a[len].next=last[x];last[x]=len;
     26      
     27     k2=++len;
     28     a[len].x=y;a[len].y=x;a[len].c=0;
     29     a[len].next=last[y];last[y]=len;
     30      
     31     a[k1].other=k2;
     32     a[k2].other=k1;
     33 }
     34 int list[11000],h[110000];
     35 bool bt_h()
     36 {
     37     memset(h,0,sizeof(h));h[st]=1;
     38     list[1]=st;head=1;tail=2;
     39     while(head!=tail)
     40     {
     41         int x=list[head];
     42         for(int k=last[x];k;k=a[k].next)
     43         {
     44             int y=a[k].y;
     45             if(h[y]==0 && a[k].c>0)
     46             {
     47                 h[y]=h[x]+1;
     48                 list[tail++]=y;
     49             }
     50         }
     51         head++;
     52     }
     53     if(h[ed]>0)return true;
     54     return false;
     55 }
     56 int find_flow(int x,int flow)
     57 {
     58     if(x==ed)return flow;
     59     int s=0,t;
     60     for(int k=last[x];k;k=a[k].next)
     61     {
     62         int y=a[k].y;
     63         if(h[y]==h[x]+1 && a[k].c>0 && s<flow)
     64         {
     65             s+=t=find_flow(y,min(a[k].c,flow-s));
     66             a[k].c-=t;a[a[k].other].c+=t;
     67         }
     68     }
     69     if(s==0)h[x]=0;
     70     return s;
     71 }
     72 int A[110][110],B[110][110],C[110][110];
     73 int f[110][110];//黑白染色 1为黑 2为白 
     74 int d[110][110];
     75 int main()
     76 {
     77     qread(n);qread(m);
     78     len=0;memset(last,0,sizeof(last));
     79     st=n*m+1;ed=st+1;
     80     int s=1;
     81     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)d[i][j]=(i-1)*m+j;
     82     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)qread(A[i][j]);
     83     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)qread(B[i][j]);
     84     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)qread(C[i][j]);
     85     memset(f,0,sizeof(f));
     86     for(int i=1;i<=n;i++)
     87         for(int j=1;j<=m;j++)
     88         {
     89             if(i==1 && j==1)continue;
     90             if(j==1)f[i][j]=f[i-1][j]^1;
     91             else f[i][j]=f[i][j-1]^1;
     92         }
     93     int sum=0;
     94     for(int i=1;i<=n;i++)
     95         for(int j=1;j<=m;j++)
     96         {
     97             sum+=A[i][j]+B[i][j];
     98             if(f[i][j]==1)
     99             {
    100                 ins(st,d[i][j],A[i][j]);
    101                 ins(d[i][j],ed,B[i][j]);
    102             }
    103             else
    104             {
    105                 ins(st,d[i][j],B[i][j]);
    106                 ins(d[i][j],ed,A[i][j]);
    107             }
    108         }
    109     for(int i=1;i<=n;i++)
    110         for(int j=1;j<=m;j++)
    111         {
    112             if(i-1>0)ins(d[i][j],d[i-1][j],C[i][j]+C[i-1][j]),sum+=C[i][j];
    113             if(i+1<=n)ins(d[i][j],d[i+1][j],C[i][j]+C[i+1][j]),sum+=C[i][j];
    114             if(j-1>0)ins(d[i][j],d[i][j-1],C[i][j]+C[i][j-1]),sum+=C[i][j];
    115             if(j+1<=m)ins(d[i][j],d[i][j+1],C[i][j]+C[i][j+1]),sum+=C[i][j];
    116         }
    117     int ans=0;
    118     while(bt_h())ans+=find_flow(st,999999999);
    119     printf("%d
    ",sum-ans);
    120     return 0;
    121 }
  • 相关阅读:
    fork和Vfork的区别
    exer4.13.c(undone)
    Exer4.6.c(undone)
    好习惯
    c语言中的register修饰符
    请教如何在页面之间传递dataSet?不用session
    ultraEdite编辑shell或perl程序时注意
    PowerBuilder程序中取数据库中值,值异常(正数变成负数或异常)
    pb程序的编译发布
    关于sql server2000 的1068 与 1069 问题
  • 原文地址:https://www.cnblogs.com/CHerish_OI/p/8126243.html
Copyright © 2011-2022 走看看