BZOJ 2127: happiness [最小割]
Posted Candy?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2127: happiness [最小割]相关的知识,希望对你有一定的参考价值。
2127: happiness
Time Limit: 51 Sec Memory Limit: 259 MBSubmit: 1815 Solved: 878
[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
1 1
100 110
1
1000
Sample Output
1210
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数
本题和上一题很相似,可以用相同的做法
但是本题可以优化
相邻两个人具有经典的棋盘黑白染色的特征,虽然本题貌似与二分图无关,这是句废话
能不能在一人一点的基础上直接处理出神秘加成
放弃文同时也是放弃了 神秘加成_文/2
两个人都放弃文就成功的放弃了整个 神秘加成_文
理同理
但是一人选文一人选理两个神秘加成都不能要啊,但这样每个神秘加成只放弃了1/2
那就再加两条边,链接相邻两个人,容量为(神秘加成_文+神秘加成_理)/2,割的时候一文一理时必定割去这条两条边之一
提示:
那两条边可以直接加无向边
注意:
煞笔Candy?数组开成[10005][10005] bzoj不是T就是M
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N=1e4+5,M=1e5+5,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();} return x*f; } int n,m,num,s,t,a[105][105],b[105][105],c,f[105][105],g[105][105],sum; struct edge{ int v,c,f,ne; }e[M<<1]; int cnt,h[N]; inline void ins(int u,int v,int c){ cnt++; e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].c=0;e[cnt].f=0;e[cnt].ne=h[v];h[v]=cnt; } inline void ins2(int u,int v,int c){ cnt++; e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[v];h[v]=cnt; } int q[N],head,tail,vis[N],d[N]; bool bfs(){ memset(vis,0,sizeof(vis)); memset(d,0,sizeof(d)); head=tail=1; d[s]=0;vis[s]=1; q[tail++]=s; while(head!=tail){ int u=q[head++]; for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(!vis[v]&&e[i].c>e[i].f){ vis[v]=1; d[v]=d[u]+1; q[tail++]=v; if(v==t) return true; } } } return false; } int cur[N]; int dfs(int u,int a){ if(u==t||a==0) return a; int flow=0,f; for(int &i=cur[u];i;i=e[i].ne){ int v=e[i].v; if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c-e[i].f)))>0){ flow+=f; e[i].f+=f; e[((i-1)^1)+1].f-=f; a-=f; if(a==0) break; } } return flow; } int dinic(){ int flow=0; while(bfs()){ for(int i=s;i<=t;i++) cur[i]=h[i]; flow+=dfs(s,INF); } return flow; } inline int id(int i,int j){return (i-1)*m+j;} int main(){ //freopen("in.txt","r",stdin); n=read();m=read(); s=0;t=n*m+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read()<<1,sum+=a[i][j]>>1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) b[i][j]=read()<<1,sum+=b[i][j]>>1; for(int i=1;i<=n-1;i++) for(int j=1;j<=m;j++){ c=read();a[i][j]+=c;a[i+1][j]+=c;sum+=c; f[i][j]+=c; //ins2(id(i,j),id(i+1,j),c); } for(int i=1;i<=n-1;i++) for(int j=1;j<=m;j++){ c=read();b[i][j]+=c;b[i+1][j]+=c;sum+=c; f[i][j]+=c; //ins2(id(i,j),id(i+1,j),c); } for(int i=1;i<=n;i++) for(int j=1;j<=m-1;j++){ c=read();a[i][j]+=c;a[i][j+1]+=c;sum+=c; g[i][j]+=c; //ins2(id(i,j),id(i,j+1),c); } for(int i=1;i<=n;i++) for(int j=1;j<=m-1;j++){ c=read();b[i][j]+=c;b[i][j+1]+=c;sum+=c; g[i][j]+=c; //ins2(id(i,j),id(i,j+1),c); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ ins(s,id(i,j),a[i][j]); ins(id(i,j),t,b[i][j]); ins2(id(i,j),id(i+1,j),f[i][j]); ins2(id(i,j),id(i,j+1),g[i][j]); } int ans=dinic(); printf("%d",sum-(ans>>1)); }
以上是关于BZOJ 2127: happiness [最小割]的主要内容,如果未能解决你的问题,请参考以下文章