【2011集训队出题】happiness
来源:互联网 发布:剑三叽太捏脸数据 编辑:程序博客网 时间:2024/05/16 11:05
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
Hint
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于10%以内的数据,n,m<=4
对于30%以内的数据,n,m<=8
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数
Solution
这一题的建模比较有创意。
考虑建立一个超级源点S和一个超级汇点T。
从S连边到某个点表示选文科,从某个点连边到T表示选理科,边权值为给定的喜悦值。
对于两个点都选文的情况,就新建一个中间点,从S连到中间点,边权为喜悦值,再从中间点连向这两个点,边权设为inf。
类似的可以处理处理科的情况。
这里的连边很关键,也不是很好想。
代码还是比较好懂的。
Code
#include <cstdio>#include <algorithm>#include <cstring>#define P(x,y) (~-(x)*m+(y)) //快速算点坐标#define fo(i,a,b) for (i=a;i<=b;i++)using namespace std;const int maxn=500000;const int inf=10000007;int n,m,i,j,p,x,tot,ans,s,t,cnt;int next[maxn],head[maxn],b[maxn],c[maxn],d[maxn],q[maxn],cur[maxn];int read(){ int su=0; char c=getchar(); while (c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') { su=su*10+c-'0'; c=getchar(); } return su;}void plus(int x,int y,int z){ next[++tot]=head[x]; head[x]=tot; b[tot]=y; c[tot]=z;}void add(int x,int y,int z){ plus(x,y,z); plus(y,x,0);}int bfs(){ int l,r,x,i; l=0,r=1; q[r]=s; memset(d,0,sizeof(d)); d[s]=1; while (l<r) { x=q[++l]; for (i=head[x];i!=-1;i=next[i]){ if (c[i]!=0&&d[b[i]]==0) { q[++r]=b[i]; d[b[i]]=d[x]+1; } } } if (d[t]>0) return 1; else return 0;} int dfs(int x,int f){ if (x==t) return f; for (int & i=cur[x];i!=-1;i=next[i]){ if ((d[b[i]]==d[x]+1)&&(c[i]!=0)){ int di=dfs(b[i],min(c[i],f)); if (di>0) { c[i]-=di;c[i^1]+=di;return di;} } } return 0;}int main(){ n=read(),m=read(); tot=-1,cnt=n*m; memset(head,-1,sizeof(head)); memset(next,-1,sizeof(next)); s=0; t=6*n*m+1; int sum; fo(i,1,n) fo(j,1,m) { x=read(); sum+=x; p=P(i,j); add(s,p,x); } fo(i,1,n) fo(j,1,m) { x=read(); sum+=x; p=P(i,j); add(p,t,x); } fo(i,1,n-1) fo(j,1,m) { x=read(); sum+=x; p=P(i,j); cnt++; add(s,cnt,x); add(cnt,p,inf); add(cnt,p+m,inf); } fo(i,1,n-1) fo(j,1,m) { x=read(); sum+=x; p=P(i,j); cnt++; add(cnt,t,x); add(p,cnt,inf); add(p+m,cnt,inf); } fo(i,1,n) fo(j,1,m-1) { x=read(); sum+=x; p=P(i,j); cnt++; add(s,cnt,x); add(cnt,p,inf); add(cnt,p+1,inf); } fo(i,1,n) fo(j,1,m-1){ x=read(); sum+=x; p=P(i,j); cnt++; add(cnt,t,x); add(p,cnt,inf); add(p+1,cnt,inf); } while (bfs()) { fo(i,s,t) cur[i]=head[i]; while (int di=dfs(s,inf)) ans+=di; } printf("%d\n",sum-ans);}
- 【2011集训队出题】happiness
- 【2011集训队出题】happiness
- [JZOJ1919] [BZOJ2127]【2011集训队出题】happiness(最小割之二元关系)
- 【2011集训队出题】圈地计划
- 【2011集训队出题】数颜色
- 【集训队出题2011】大楼 题解
- [国家集训队2011]happiness(吴确)…
- 【COGS 1873】 [国家集训队2011]happiness(吴确)
- 最小割 [国家集训队2011]happiness(吴确)
- 【国家集训队2011】happiness 网络最大流
- [国家集训队2011]happiness(吴确) (最小割)
- 【数学】2011集训队出题 跳跳棋
- 【2011集训队出题】Crash的数字表格
- 【2011集训队出题】Crash的数字表格
- 【2011集训队出题】【GDKOI2010】圈地计划
- JZOJsenior1935.【2011集训队出题】单选错位
- jzoj1916 [2011集训队出题] 飞飞侠 spfa
- jzoj1935 [2011集训队出题] 单选错位 概率水题
- Rstudio中配置环境实现动态报告
- Opencv: pointPolygonTest函数使用
- 泛型依赖注入
- 算法竞赛入门经典几个有意思的问题
- 面向对象加强1
- 【2011集训队出题】happiness
- 使用nutz进行简单的增删查改操作
- vue的理解
- CGTime CMTimeRange CMTimeMapping 小结
- python/folium绘制中国人口数量热力图(HeatMap)
- 数据结构实验之排序四:寻找大富翁__咳咳咳,还魂篇!!
- 魔方阵
- 如何在科技论文中使用时态
- Lintcode 15. 全排列