bzoj3894: 文理分科(还是那道最小割)

3894: 文理分科

题目:传送门

 

感谢波老师没有来D飞我,让我做出了这题...

题解:

   这题其实和我做的上一题(bzoj2132)很像,所以就不写题意了。

   依然是那最小割...

   这题给出了四个利益矩阵,看似比上一题复杂,想了很久,发现其实建图没有我想象的麻烦。

   首先复习一下最小割的定义:把原图分为两个不相交的子集(st和ed)

   那么这题用最小割来做的话,我们就把st当成文科的子集,ed为理科。

   对于任意的一个x点

   st到x连一条流量为文科利益的边,x到ed连一条流量为理科利益的边

   那么另外两个利益矩阵怎么处理呢?这里我们就要手动建一些新点

   对于任意的一个十字,这个十字中的点都是互相影响的,那么我们用一个新点分别连向十字中的所有点,流量为无限,然后st想这个新点连,流量为同选文科的利益

   再建一匹新点:

   对于任意的一个十字,这个十字中的点都是互相影响的,那么我们把十字中的所有点都想一个新点连边,流量为无限,然后这个新点向ed连,流量为同选理科的利益

   原理就YY吧。。。

 

上代码:

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cmath>
  5 #include<algorithm>
  6 #define inf 999999999
  7 #define qread(x)x=read();
  8 using namespace std;
  9 inline int read()
 10 {
 11     int f=1,x=0;char ch;
 12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 14     return f*x;
 15 }
 16 const int dx[5]={0,-1,1,0,0};
 17 const int dy[5]={0,0,0,-1,1};
 18 struct node
 19 {
 20     int x,y,c,next,other;
 21 }a[2100000];int len,last[1100000];
 22 int n,m,st,ed,head,tail;
 23 void ins(int x,int y,int c)
 24 {
 25     int k1,k2;
 26     k1=++len;
 27     a[len].x=x;a[len].y=y;a[len].c=c;
 28     a[len].next=last[x];last[x]=len;
 29      
 30     k2=++len;
 31     a[len].x=y;a[len].y=x;a[len].c=0;
 32     a[len].next=last[y];last[y]=len;
 33      
 34     a[k1].other=k2;
 35     a[k2].other=k1;
 36 }
 37 int list[1100000],h[1100000];
 38 bool bt_h()
 39 {
 40     memset(h,0,sizeof(h));h[st]=1;
 41     list[1]=st;head=1;tail=2;
 42     while(head!=tail)
 43     {
 44         int x=list[head];
 45         for(int k=last[x];k;k=a[k].next)
 46         {
 47             int y=a[k].y;
 48             if(h[y]==0 && a[k].c>0)
 49             {
 50                 h[y]=h[x]+1;
 51                 list[tail++]=y;
 52             }
 53         }
 54         head++;
 55     }
 56     if(h[ed]>0)return true;
 57     return false;
 58 }
 59 int find_flow(int x,int flow)
 60 {
 61     if(x==ed)return flow;
 62     int s=0,t;
 63     for(int k=last[x];k;k=a[k].next)
 64     {
 65         int y=a[k].y;
 66         if(h[y]==h[x]+1 && a[k].c>0 && s<flow)
 67         {
 68             s+=t=find_flow(y,min(a[k].c,flow-s));
 69             a[k].c-=t;a[a[k].other].c+=t;
 70         }
 71     }
 72     if(s==0)h[x]=0;
 73     return s;
 74 }
 75 int w[110][110],l[110][110],sw[110][110],sl[110][110];
 76 int d[110][110];
 77 int main()
 78 {
 79     qread(n);qread(m);
 80     st=n*m*3+1;ed=st+1;
 81     len=0;memset(last,0,sizeof(last));
 82     int ss=1;
 83     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)d[i][j]=ss++;
 84     int sum=0;
 85     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){qread(w[i][j]);ins(st,d[i][j],w[i][j]);sum+=w[i][j];}
 86     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){qread(l[i][j]);ins(d[i][j],ed,l[i][j]);sum+=l[i][j];}
 87     for(int i=1;i<=n;i++)
 88         for(int j=1;j<=m;j++)
 89         {
 90             qread(sw[i][j]);
 91             for(int k=0;k<=4;k++)
 92                 if(d[i+dx[k]][j+dy[k]]>0)
 93                     ins(d[i][j]+n*m,d[i+dx[k]][j+dy[k]],inf);
 94             ins(st,d[i][j]+n*m,sw[i][j]);
 95             sum+=sw[i][j];
 96         }
 97     for(int i=1;i<=n;i++)
 98         for(int j=1;j<=m;j++)
 99         {
100             qread(sl[i][j]);
101             for(int k=0;k<=4;k++)
102                 if(d[i+dx[k]][j+dy[k]]>0)
103                     ins(d[i+dx[k]][j+dy[k]],d[i][j]+n*m*2,inf);
104             ins(d[i][j]+n*m*2,ed,sl[i][j]);
105             sum+=sl[i][j];
106         }
107     int ans=0;
108     while(bt_h())ans+=find_flow(st,inf);
109     printf("%d\n",sum-ans);
110     return 0;
111 }

 

posted @ 2017-12-27 16:24  CHerish_OI  阅读(402)  评论(0编辑  收藏  举报