bzoj 2127(最小割)

11 篇文章 0 订阅

2127: happiness

Time Limit: 51 Sec   Memory Limit: 259 MB
Submit: 1397   Solved: 676
[ Submit][ Status][ Discuss]

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的非负整数


解题思路:对于两种之间选的题目想到网络流,再因为只能选一个,就用最小割。

求最大的话先算总的再减最小割。

利用最小割考虑。

对于原图中所有相邻的两个人A,B,我们建边:

s->A:cost[A文]+c[文][A][B]/2,s->B:cost[B文]+c[文][A][B]/2;

A->t:cost[A理]+c[理][A][B]/2,B->t:costB[理]+c[理][A][B]/2;

A<–>B:c[文][A][B]/2+c[理][A][B]/2

这样会出现两种割,分别对应两种相同,一种选文一种选理。


太坑了。注意每个点只需要一条边。否则cost要重复计算。



#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,len=1,T,tot,ans;
int to[300001],zhi[300001],next[300001];
int h[11000],dis[11000];
int q[11000],chi[11000],mat[11000],pre[11000],ptu[11000],pgg[11000],ptu2[11000],pgg2[11000];


inline int read()
{
char y;int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}


void insert(int x,int y,int z)
 {
  ++len; to[len]=y; zhi[len]=z; next[len]=h[x]; h[x]=len;
 }


bool bfs()
 {
  memset(dis,-1,sizeof(dis));
  dis[0]=1; int tail=1,head=0; q[tail]=0;
  while (head<tail)
  {
  ++head;
  int u=h[q[head]];
  while (u!=0)
  {
    if (dis[to[u]]==-1 && zhi[u]>0)
     {
       dis[to[u]]=dis[q[head]]+1;
       ++tail; q[tail]=to[u];
}
 u=next[u];
}
 }
if (dis[T]==-1) return false;else return true;
 }


int dicnic(int sum,int now)
 {
  if (now==T) return sum;
  int sug=0;
  int u=h[now];
  while (u!=0)
  {
  if (zhi[u]>0 && dis[now]+1==dis[to[u]])
  {
  int s=dicnic(min(sum-sug,zhi[u]),to[u]);
  if (s>0)
  {
  sug+=s;
  zhi[u]-=s; zhi[u^1]+=s;
  if (sug==sum) return sum;
}
}
u=next[u];
 }
if (sug==0) dis[now]=-1;
return sug;
 }


int main()
{
n=read(); m=read();
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
 {
  chi[(i-1)*m+j]=read();
 }
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
 {
  mat[(i-1)*m+j]=read();
 }
T=n*m+1;
for (int i=1;i<=n-1;++i)
{
  for (int j=1;j<=m;++j)
   {
   int x=read();
   int u1=(i-1)*m+j; int u2=u1+m;
   if (ptu[u1]!=0) { tot+=x; zhi[ptu[u1]]+=x;}else
    {insert(0,u1,2*chi[u1]+x); insert(u1,0,0); tot+=2*chi[u1]+x;ptu[u1]=len-1;}
   if (ptu[u2]!=0) { tot+=x; zhi[ptu[u2]]+=x;}else
    {insert(0,u2,2*chi[u2]+x); insert(u2,0,0); tot+=2*chi[u2]+x;ptu[u2]=len-1;}
   insert(u1,u2,x); insert(u2,u1,x); pre[u1]=len;
 } 
    }
for (int i=1;i<=n-1;++i)
for (int j=1;j<=m;++j)
 {
  int x=read();
  int u1=(i-1)*m+j; int u2=u1+m;
  if (pgg[u1]!=0) { tot+=x; zhi[pgg[u1]]+=x;}else
    {insert(u1,T,2*mat[u1]+x); insert(T,u1,0); tot+=2*mat[u1]+x;pgg[u1]=len-1;}
   if (pgg[u2]!=0) { tot+=x; zhi[pgg[u2]]+=x;}else
    {insert(u2,T,2*mat[u2]+x); insert(T,u2,0); tot+=2*mat[u2]+x;pgg[u2]=len-1;}
  zhi[pre[u1]]+=x; zhi[pre[u1]^1]+=x;
 }
for (int i=1;i<=n;++i)
for (int j=1;j<=m-1;++j)
 {
  int x=read();
  int u1=(i-1)*m+j; int u2=u1+1;
  if (ptu[u1]!=0) { tot+=x; zhi[ptu[u1]]+=x;}else
    {insert(0,u1,2*chi[u1]+x); insert(u1,0,0); tot+=2*chi[u1]+x;ptu[u1]=len-1;}
   if (ptu[u2]!=0) { tot+=x; zhi[ptu[u2]]+=x;}else
    {insert(0,u2,2*chi[u2]+x); insert(u2,0,0); tot+=2*chi[u2]+x;ptu[u2]=len-1;}
  insert(u1,u2,x); insert(u2,u1,x); pre[u1]=len;
 }
for (int i=1;i<=n;++i)
for (int j=1;j<=m-1;++j)
 {
  int x=read();
  int u1=(i-1)*m+j; int u2=u1+1;
  if (pgg[u1]!=0) { tot+=x; zhi[pgg[u1]]+=x;}else
    {insert(u1,T,2*mat[u1]+x); insert(T,u1,0); tot+=2*mat[u1]+x;pgg[u1]=len-1;}
   if (pgg[u2]!=0) { tot+=x; zhi[pgg[u2]]+=x;}else
    {insert(u2,T,2*mat[u2]+x); insert(T,u2,0); tot+=2*mat[u2]+x;pgg[u2]=len-1;}
  zhi[pre[u1]]+=x; zhi[pre[u1]^1]+=x;
 }
     ans=0;
     while (bfs())
      {
      ans+=dicnic(0x7fffffff,0);
 }
printf("%d",(tot-ans)>>1);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值