【TYVJ】1338 QQ农场(最大流+最大权闭合图)
http://tyvj.cn/Problem_Show.aspx?id=1338
时间才排到rank7,还不快啊囧。isap我常数都写得那么小了。。。
最大权闭合图看我另一篇博文吧
此题很明显的模型。
首先我们先染色,使整个图黑白相间,其中我们只需要在黑色点向对应的上下左右白色节点连边,很明显,这些节点都有权值,我们需要求的是最大权,那么就按我的博文那样来做即可。
upd:本题并不是裸的最大权闭合图模型,而是最小割模型,即我们将问题转换为:去掉“同时取冲突的格子”的情况得到“不冲突”。即最小化“同时取冲突的格子”,将所有格子放到一个流网络,其中s连接白(黑)格子,t连接黑(白)格子,相邻的黑白格子连接容量oo,那么一个最小割[s, t]对应一个简单割,且简单割对应一种方案。
用sum-最小割就是答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> using namespace std; #define rep(i, n) for(int i=0; i<(n); ++i) #define for1(i,a,n) for(int i=(a);i<=(n);++i) #define for2(i,a,n) for(int i=(a);i<(n);++i) #define for3(i,a,n) for(int i=(a);i>=(n);--i) #define for4(i,a,n) for(int i=(a);i>(n);--i) #define CC(i,a) memset(i,a,sizeof(i)) #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define read(a) a=getnum() #define print(a) printf("%d", a) inline int getnum() { int ret=0; char c; for (c= getchar (); c< '0' || c> '9' ; c= getchar ()); for (; c>= '0' && c<= '9' ; c= getchar ()) ret=ret*10+c- '0' ; return ret; } const int N=40005, M=N*4*2, oo=~0u>>2; int ihead[N], inext[M], from[M], to[M], cap[M], cnt=1; int gap[N], d[N], cur[N], p[N]; inline void add( const int &u, const int &v, const int &w) { inext[++cnt]=ihead[u]; ihead[u]=cnt; from[cnt]=u; to[cnt]=v; cap[cnt]=w; inext[++cnt]=ihead[v]; ihead[v]=cnt; from[cnt]=v; to[cnt]=u; cap[cnt]=0; } inline int isap( const int &s, const int &t, const int &n) { int u=s, f, i, flow=0; for1(i, 0, n) cur[i]=ihead[i]; gap[0]=n; while (d[s]<n) { for (i=cur[u]; i; i=inext[i]) if (cap[i] && d[u]==d[to[i]]+1) break ; if (i) { cur[u]=i; p[to[i]]=i; u=to[i]; if (u==t) { for (f=oo; u!=s; u=from[p[u]]) f=min(f, cap[p[u]]); for (u=t; u!=s; u=from[p[u]]) cap[p[u]]-=f, cap[p[u]^1]+=f; flow+=f; } } else { if (!(--gap[d[u]])) break ; d[u]=n; cur[u]=ihead[u]; for (i=ihead[u]; i; i=inext[i]) if (cap[i] && d[u]>d[to[i]]+1) d[u]=d[to[i]]+1; ++gap[d[u]]; if (u!=s) u=from[p[u]]; } } return flow; } int main() { int t, u, n; read(n); int S=0, T=n*n+1; int sum=0, last; for1(i, 1, n) { last=i; for1(j, 1, n) { read(t); sum+=t; u=(i-1)*n+j; if (last%2) { if (i>1) add(u, u-n, oo); if (i<n) add(u, u+n, oo); if (j>1) add(u, u-1, oo); if (j<n) add(u, u+1, oo); add(S, u, t); } else add(u, T, t); ++last; } } printf ( "%d\n" , sum-isap(S, T, T+1)); return 0; } |
背景 Background
Sandytea前段时间沉迷于QQ农场中……一天夜里,他梦见来到好友X的农场上……描述 Description
这个农场和游戏中略有不同。土地实际上是一个边长为N的正方形,由N*N块土地组成。在每块土地上,都种有一种农作物。如果他选择摘取一块土地上的农作物,就能获得一个固定的利润(当然,这个利润是正数)。不同土地上的利润多半是不同的。
贪心的Sandytea本想摘取所有土地上的农作物。但是正当他准备行动时,却被告知不允许摘取了两块有公共边的土地上的作物,否则就会被主人的狗发现。
Sandytea想知道,在不被狗抓住的前提下,他能获得的最大利益是多少。
输入格式 InputFormat
第一行:一个整数N,表示土地是一个边长为N的正方形。下面N行:每行N个正整数,描述了各块土地上的农作物的单位价值。
输出格式 OutputFormat
输出一行,包含一个整数,为最大的收益。样例输入 SampleInput [复制数据]
2
7 7
54 54
样例输出 SampleOutput [复制数据]
61
数据范围和注释 Hint
数据范围:有10分的数据满足:N≤6
另有20分的数据满足:N≤13
另有30分的数据满足:N≤50
另有40分的数据满足:N≤200
所有数据满足:每块土地上作物的价值不超过100。
来源 Source
改编自SPOJ
博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步