BZOJ2127: happiness

2127: happiness

Time Limit: 51 Sec  Memory Limit: 259 MB
Submit: 605  Solved: 283
[Submit][Status]

Description

高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。

Input

第一行两个正整数n,m。接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值。第二个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择理科获得的喜悦值。第三个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择文科获得的额外喜悦值。第四个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择理科获得的额外喜悦值。第五个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择文科获得的额外喜悦值。第六个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择理科获得的额外喜悦值。

Output

输出一个整数,表示喜悦值总和的最大值

Sample Input

1 2
1 1
100 110
1
1000

Sample Output

1210
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数

HINT

 

Source

题解:

就算是我懂了。。。

 

搬运题解:

首先发现题目出现了很明显的二分图关系--选文科还是理科,很明显是一个网络流问题,联系到题目上的一个人选文科还是理科可以得到一定喜悦值,两个人同时选文科还是理科,又可以得到一定喜悦值,发现最终答案是由每个人选文科,还是选理科,这个行为确定的,与最小割有一定关系。

     继续观察,如果按最小割建立模型,每个人选文选理的代价可以在与s,t的连边上体现,这时难点就变成了如何体现两个人之间的关系:同时选文或选理需要的代价。

   这时引入一个很神奇的东西,无向边。

   这个东西是我在clj的ppt上看见的,有一个很有用的作用:若A<-->B:C,即A与B连一条权值为C的无向边,当这条无向边计入最小割时,表示这两个点分属于s,t两个集合。

   但是仅仅知道如此是不够的,因为对于A,B两点,如果他们都属于S集合,即与T集合的边已经计入最小割了,那A与B之间的边就一定不会出现在最小割里,这一点可以作图验证一二。

   所以我们应该对原图进行一定变换。注意到这里我们是想将两个点之间的关系体现在同时取s集或同时取t集的情况,即与s,与t的连接边:若A与B同时选文得到W1的喜悦值,同时选理得到W2的喜悦值,S->A:w1/2,A->T:w2/2,

S->B:w1/2,B->T:w2/2,A<-->B:(w1+w2)/2。

   为什么呢?自己画图验证,很神奇的东西,特别难想,不过做过一遍以后再做就觉得很容易了。

 

似乎从最小割的含义来考虑是显然的?毕竟我还太弱。。。

代码:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<iostream>
  7 #include<vector>
  8 #include<map>
  9 #include<set>
 10 #include<queue>
 11 #include<string>
 12 #define inf 1000000000
 13 #define maxn 100000
 14 #define maxm 500000
 15 #define eps 1e-10
 16 #define ll long long
 17 #define pa pair<int,int>
 18 #define rep(x,y) for(int i=1;i<=x;i++)for(int j=1;j<=y;j++)
 19 #define FOR for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
 20 #define mod 1000000007
 21 using namespace std;
 22 inline int read()
 23 {
 24     int x=0,f=1;char ch=getchar();
 25     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 26     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 27     return x*f;
 28 }
 29 int  n,m,s,t,maxflow,cnt=1,tot,a[105][105],b[105][105],mark[105][105],head[maxn],cur[maxn],h[maxn],q[maxn];
 30 struct edge{int go,next,v;}e[maxm];
 31 void ins(int x,int y,int z){e[++cnt].go=y;e[cnt].v=z;e[cnt].next=head[x];head[x]=cnt;}
 32 void insert(int x,int y,int z){ins(x,y,z);ins(y,x,0);}
 33 void ins2(int x,int y,int z){insert(x,y,z);insert(y,x,z);}
 34 bool bfs()
 35 {
 36     for(int i=s;i<=t;i++)h[i]=-1;
 37     int l=0,r=1;q[1]=s;h[s]=0;
 38     while(l<r)
 39     {
 40         int x=q[++l];
 41         for(int i=head[x];i;i=e[i].next)
 42          if(e[i].v&&h[e[i].go]==-1)
 43          {
 44             h[e[i].go]=h[x]+1;q[++r]=e[i].go;
 45          }
 46     }
 47     return h[t]!=-1;
 48 }
 49 int dfs(int x,int f)
 50 {
 51     if(x==t) return f;
 52     int tmp,used=0;
 53     for(int i=head[x];i;i=e[i].next)
 54      if(e[i].v&&h[e[i].go]==h[x]+1)
 55     {
 56         tmp=dfs(e[i].go,min(e[i].v,f-used));
 57         e[i].v-=tmp;if(e[i].v)cur[x]=i;
 58         e[i^1].v+=tmp;used+=tmp;
 59         if(used==f)return f;       
 60     }
 61     if(!used) h[x]=-1;
 62     return used;
 63 }
 64 void dinic()
 65 {
 66     maxflow=0;
 67     while(bfs())
 68     {
 69         for (int i=s;i<=t;i++)cur[i]=head[i];maxflow+=dfs(s,inf);
 70     }
 71 }
 72 int main()
 73 {
 74     freopen("input.txt","r",stdin);
 75     freopen("output.txt","w",stdout);
 76     n=read();m=read();
 77     FOR a[i][j]=read(),tot+=a[i][j],a[i][j]<<=1;
 78     FOR b[i][j]=read(),tot+=b[i][j],b[i][j]<<=1;
 79     FOR mark[i][j]=(i-1)*m+j;
 80     s=0;t=mark[n][m]+1;
 81     int x;
 82     rep(n-1,m)
 83     {
 84        x=read();tot+=x;
 85        a[i][j]+=x;a[i+1][j]+=x;
 86        ins2(mark[i][j],mark[i+1][j],x);
 87     }
 88     rep(n-1,m)
 89     {
 90        x=read();tot+=x;
 91        b[i][j]+=x;b[i+1][j]+=x;
 92        ins2(mark[i][j],mark[i+1][j],x);
 93     }
 94     rep(n,m-1)
 95     {
 96        x=read();tot+=x;
 97        a[i][j]+=x;a[i][j+1]+=x;
 98        ins2(mark[i][j],mark[i][j+1],x);
 99     }
100     rep(n,m-1)
101     {
102        x=read();tot+=x;
103        b[i][j]+=x;b[i][j+1]+=x;
104        ins2(mark[i][j],mark[i][j+1],x);
105     }
106     FOR{
107            insert(s,mark[i][j],a[i][j]);
108            insert(mark[i][j],t,b[i][j]);
109        }
110     dinic();
111     printf("%d\n",tot-(maxflow>>1));
112     return 0;
113 }
View Code

 UPD:

写了下另一种解法:

考虑同桌同选文科的额外收获w,

我们新建一个节点x,连边s-> 容量为w,

x到u,v容量为inf。

当w算入割的时候u,v都属于t割,即选了文科。

这种方法新建了很多新点,虽然速度慢,但是好理解。

代码:

  1 #include<cstdio>
  2 
  3 #include<cstdlib>
  4 
  5 #include<cmath>
  6 
  7 #include<cstring>
  8 
  9 #include<algorithm>
 10 
 11 #include<iostream>
 12 
 13 #include<vector>
 14 
 15 #include<map>
 16 
 17 #include<set>
 18 
 19 #include<queue>
 20 
 21 #include<string>
 22 
 23 #define inf 1000000000
 24 
 25 #define maxn 200000+5
 26 
 27 #define maxm 500000+5
 28 
 29 #define eps 1e-10
 30 
 31 #define ll long long
 32 
 33 #define pa pair<int,int>
 34 
 35 #define for0(i,n) for(int i=0;i<=(n);i++)
 36 
 37 #define for1(i,n) for(int i=1;i<=(n);i++)
 38 
 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 40 
 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 42 
 43 #define for4(i,x) for(int i=head[x],y;i;i=e[i].next)
 44 #define for5(n,m) for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
 45 
 46 #define mod 1000000007
 47 
 48 using namespace std;
 49 int  n,m,s,t,cnt,sum,maxflow,tot=1,head[maxn],cur[maxn],h[maxn],num[150][150];
 50 queue<int>q;
 51 struct edge{int go,next,v;}e[maxm];
 52 
 53 inline int read()
 54 
 55 {
 56 
 57     int x=0,f=1;char ch=getchar();
 58 
 59     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 60 
 61     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 62     sum+=x*f;
 63 
 64     return x*f;
 65 
 66 }
 67 inline void add(int x,int y,int v)
 68 {
 69     e[++tot]=(edge){y,head[x],v};head[x]=tot;
 70     e[++tot]=(edge){x,head[y],0};head[y]=tot;
 71 }
 72 bool bfs()
 73 {
 74     for(int i=s;i<=t;i++)h[i]=-1;
 75     q.push(s);h[s]=0;
 76     while(!q.empty())
 77     {
 78         int x=q.front();q.pop();
 79         for(int i=head[x];i;i=e[i].next)
 80          if(e[i].v&&h[e[i].go]==-1)
 81          {
 82             h[e[i].go]=h[x]+1;q.push(e[i].go);
 83          }
 84     }
 85     return h[t]!=-1;
 86 }
 87 int dfs(int x,int f)
 88 {
 89     if(x==t) return f;
 90     int tmp,used=0;
 91     for(int i=cur[x];i;i=e[i].next)
 92      if(e[i].v&&h[e[i].go]==h[x]+1)
 93     {
 94         tmp=dfs(e[i].go,min(e[i].v,f-used));
 95         e[i].v-=tmp;if(e[i].v)cur[x]=i;
 96         e[i^1].v+=tmp;used+=tmp;
 97         if(used==f)return f;       
 98     }
 99     if(!used) h[x]=-1;
100     return used;
101 }
102 void dinic()
103 {
104     maxflow=0;
105     while(bfs())
106     {
107         for (int i=s;i<=t;i++)cur[i]=head[i];maxflow+=dfs(s,inf);
108     }
109 }
110 
111 int main()
112 
113 {
114 
115     freopen("input.txt","r",stdin);
116 
117     freopen("output.txt","w",stdout);
118 
119     n=read();m=read();sum=0;s=0;t=5*n*m+1;
120     for5(n,m)num[i][j]=(i-1)*m+j;cnt=num[n][m];
121     for5(n,m)add(s,num[i][j],read());
122     for5(n,m)add(num[i][j],t,read());
123     for5(n-1,m)
124     {
125         add(s,++cnt,read());
126         add(cnt,num[i][j],inf);
127         add(cnt,num[i+1][j],inf);
128     }
129     for5(n-1,m)
130     {
131         add(++cnt,t,read());
132         add(num[i][j],cnt,inf);
133         add(num[i+1][j],cnt,inf);
134     }
135     for5(n,m-1)
136     {
137         add(s,++cnt,read());
138         add(cnt,num[i][j],inf);
139         add(cnt,num[i][j+1],inf);
140     }
141     for5(n,m-1)
142     {
143         add(++cnt,t,read());
144         add(num[i][j],cnt,inf);
145         add(num[i][j+1],cnt,inf);
146     }
147     dinic();
148     printf("%d\n",sum-maxflow);
149 
150     return 0;
151 
152 }  
View Code

 

posted @ 2014-10-18 16:09  ZYF-ZYF  Views(263)  Comments(0Edit  收藏  举报