传送门:https://284914869.github.io/AEoj/558.html

题目简述 

一个人在一个n * m棋盘上玩游戏,想要占领一个格子有两个方法:

在这个格子放一个棋子。
  这个格子周围(四联通)的格子中**都有棋子**。

在(i, j)中放棋子需要花费cost[i][j],占领(i, j)能获得benefit[i][j]。求一种放置棋子的方法,使得总收益(收益 - 花费)最大。

2<=n,m<=20

分析

一眼看上去,

状压?

我是不是dp学傻了。。根本想不出

网络流?

嗯,此题是一道非常套路的网络流练习题。

如果想不到对棋盘进行黑白染色,就GG了。

所以套路之一,你要对棋盘进行黑白染色,黑点放一边,白点放一边。

感受一下,肯定是建个图,连一些收益边、花费边,跑一遍最大流来求最小割之类的。

套路之二,引用一段zzx的话:“

要验证你建出来的图是否正确也很容易,

只要看看当你选择保留某条收益边的时候,会要割掉哪些边。

假如需要割边的情况和题目要求一致,这个图就建对了。”

如何建边?

我来讲一下我的心路历程。。。(毕竟我是一个网络流萌新,这应该是我做过的第5道网络流题目)。

首先,

我们先把所有收益算上,不算任何花费。这显然是不合法的,

所以建的图要满足,当收益与花费不合法的情况下,还能继续找到从源点到汇点的一条流量>0的路径。

这时需要割去一些边(增加花费,或减少收益),使得收益与花费合法,且割去的边权值和最小(即总收益最大),这就是最小割。

对于花费边,

某一个格子,得到它的收益,一种情况是用该格子的花费,还有一种情况是用与它相邻的四个格子的花费。

由于已经进行黑白染色,该格子与相邻四个格子的颜色不同。

那么可以脑补出下图:

图中0是源点,6是汇点。

左图中,可以选择割0-1,即用1的花费,或选择割2-6,3-6,4-6,5-6,即用相邻四个格子的花费。

考虑这样还没完,因为你也可以选择放弃这个格子的收益。

同时我们又不能再加一条收益边与上图串联,

因为放弃这个格子的收益,代表着相邻的格子的收益必须要靠它自己的花费。所以简单的串联很显然是不对的。

所以我们考虑,割掉1的收益边之后,左图不存在流量>0的路,但对右图没有影响。

于是诞生了下图的连边方式:

简单地说,就是把所有的点都拆成两个点,两个点之间连收益边。

如图中一号收益边,割去之后,不存在经过 1‘ 到汇点的路,但依然存在经过1,9,8,7再经过2再到汇点的路。这样就合法了。

题外话:

一开始以为输入的字符,A-Z代表10~35,a-z代表36-61,写完代码之后发现一直wa,过了好久发现自己搞反了

之后又把数组开小了。。。。真难过

代码:

 #include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define _CLASSNAME_ SurroundingGame
#define _METHODNAME_ maxScore
#define _RC_ int
#define _METHODPARMS_ vector <string> cost, vector <string> benefit
#define ref(i,x,y)for(int i=x;i<=y;++i)
#define def(i,x,y)for(int i=x;i>=y;--i)
const int inf = (int)1e9;
int n, m, op, ed, w1[][], w2[][];
int cnt, head[], d[][] = { {,},{,},{-,},{,-} };
struct edge {
int to, next, s;
edge() {}
edge(int a, int b, int c) : to(a), next(b), s(c) {}
}e[];
int p(int x, int y, int s) {
return s*n*m + (x - )*m + y + ;
}
void Add(int x, int y, int s) {
//if (x > ed || y > ed || x<1||y<1) { cout << "err" << endl; }
//cout << x << " " << y << " " << s << endl;
e[++cnt] = edge(y, head[x], s); head[x] = cnt;
e[++cnt] = edge(x, head[y], ); head[y] = cnt;
}
void build() {
memset(head, , sizeof head);
memset(e, , sizeof e);
cnt = ;
op = p(, , ) - , ed = p(n, m, ) + ;
ref(i, , n) ref(j, , m) {
if ((i & ) == (j & )) {
Add(op, p(i, j, ), w1[i][j]);
Add(p(i, j, ), p(i, j, ), w2[i][j]);
ref(k, , ) {
int I = i + d[k][], J = j + d[k][];
if (I< || J< || I>n || J>m)continue;
Add(p(i, j, ), p(I, J, ), inf);
}
}
else {
Add(p(i, j, ), ed, w1[i][j]);
Add(p(i, j, ), p(i, j, ), w2[i][j]);
ref(k, , ) {
int I = i + d[k][], J = j + d[k][];
if (I< || J< || I>n || J>m)continue;
Add(p(I, J, ), p(i, j, ), inf);
}
}
}
}
int ans, flow[], pre[]; bool vis[];
void work() {
while () {
//cout << ans << endl;
memset(flow, , sizeof flow);
memset(pre, , sizeof pre);
memset(vis, , sizeof vis);
flow[op] = inf;
int o, f;
while () {
o = ; f = ;
ref(i, op, ed)if (!vis[i] && flow[i] > f)
f = flow[i], o = i;
if (o == || o == ed)break;
vis[o] = ;
for (int i = head[o]; i; i = e[i].next) {
int v = e[i].to; if (vis[v])continue;
int s = min(f, e[i].s); if (s <= flow[v])continue;
flow[v] = s; pre[v] = i;
//if (v > ed) { cout << "err" << endl; }
}
}
if (o == )break;
for (; o != op; o = e[pre[o] ^ ].to) {
e[pre[o]].s -= f; e[pre[o] ^ ].s += f;
}
ans -= f;
}
//cout << ans << endl;
}
int chd(char c) {
if (c >= ''&&c <= '')return c - '';
if (c >= 'a'&&c <= 'z')return c - 'a' + ;
if (c >= 'A'&&c <= 'Z')return c - 'A' + ;
}
class _CLASSNAME_ {
public:
_RC_ _METHODNAME_(_METHODPARMS_) {
memset(w1, , sizeof w1);
memset(w2, , sizeof w2);
ans = ;
n = cost.size();
m = cost[].size();
ref(i, , n)ref(j, , m) {
w1[i][j] = chd(cost[i - ][j - ]);
w2[i][j] = chd(benefit[i - ][j - ]);
ans += w2[i][j];
}
build();
work();
return _RC_(ans);
} // BEGIN CUT HERE
public:
void run_test(int Case) { if ((Case == -) || (Case == )) test_case_0(); if ((Case == -) || (Case == )) test_case_1(); if ((Case == -) || (Case == )) test_case_2(); if ((Case == -) || (Case == )) test_case_3(); if ((Case == -) || (Case == )) test_case_4(); if ((Case == -) || (Case == )) test_case_5();}
private:
template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
void test_case_0() { string Arr0[] = { "","" }; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); string Arr1[] = { "","" }; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[]))); int Arg2 = ; verify_case(, Arg2, maxScore(Arg0, Arg1)); }
void test_case_1() { string Arr0[] = { "ZZ","ZZ" }; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); string Arr1[] = { "","" }; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[]))); int Arg2 = ; verify_case(, Arg2, maxScore(Arg0, Arg1)); }
void test_case_2() { string Arr0[] = { "XXX","XXX","XXX" }; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); string Arr1[] = { "aaa","aZa","aaa" }; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[]))); int Arg2 = ; verify_case(, Arg2, maxScore(Arg0, Arg1)); }
void test_case_3() { string Arr0[] = { "asam","atik" }; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); string Arr1[] = { "123A","45BC" }; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[]))); int Arg2 = ; verify_case(, Arg2, maxScore(Arg0, Arg1)); }
void test_case_4() {
string Arr0[] = { "IIIIIIII",
"IIWWWWII",
"IIWIIIII",
"IIWIIIII",
"IIWWWWII",
"IIIIIWII",
"IIIIIWII",
"IIWWWWII",
"IIIIIIII" }
; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); string Arr1[] = { "IIIIIIII",
"II0000II",
"II0II0II",
"II0II0II",
"II0000II",
"II0II0II",
"II0II0II",
"II0000II",
"IIIIIIII" }
; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[]))); int Arg2 = ; verify_case(, Arg2, maxScore(Arg0, Arg1));
}
void test_case_5() {
string Arr0[] = { "ej8i1lj87i54767cbkla",
"7m4l31ehe4c337k9lee6",
"4h24Z91ab8a649dacmc4",
"0f0631g78g8461jk8i4c",
"baf21g6g5a6c75Z8a3ke",
"7f957i0ib888ed1k06ga",
"j2cb87d949ghkifg3m1i",
"fi53Zee4ij8ded796l6b",
"k015e95m415gbgkml29m",
"aidlk9kmj2lkdbZ4digm",
"he67f0clim758be5a69a",
"03i54c218elje2kbl5im",
"djjjZb36l124012c7fdb",
"jhe38eh2i1fi3l061hk6",
"216i59211a67g3Z0934c",
"db5kbmjm1e3be4l8bml0",
"h22ee7gm20j82mmg6eh0",
"89aiY4c7a1cg41d1ahck",
"lcma6i2171kjk7l9h65l",
"lmhif2m96098g6Z84ka3" }; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[])));
string Arr1[] = { "a97e5100a1b45d9ae663", "897696a9c2fc8fe803ea", "03te33c97c81af5b9a26", "3743f85dd2b87b1cd20f", "3dl3a00f706b4217f220", "5a71bdadpf4bc48db593", "02l52900cca45f348dac", "cc3dd16b08c837142ada", "A70e94239c87af935b50", "f0be492c0bda3b0b4062", "050838039967e420cc98", "eed15ec303858d472304", "090b0607f91515ef4537", "cae6ebb4096e73429695", "0cH554009df2a470cd15", "36c976d9096f5c4a4c40", "06690c3b3c585207c46d", "08779dd1a5131a60122e", "D7099feb596918e9324e", "ddd3785103238eac8ef8" };
vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[])));
int Arg2 = ; verify_case(, Arg2, maxScore(Arg0, Arg1));
} // END CUT HERE
};
// BEGIN CUT HERE
int main() {
cout << "This is SurroundingGame" << endl;
SurroundingGame ___test;
___test.run_test(-);
getchar();
return ;
}
// END CUT HERE

TopCoder SRM 558 Div 1 - Problem 1000 SurroundingGame的更多相关文章

  1. TopCoder SRM 560 Div 1 - Problem 1000 BoundedOptimization & Codeforces 839 E

    传送门:https://284914869.github.io/AEoj/560.html 题目简述: 定义"项"为两个不同变量相乘. 求一个由多个不同"项"相 ...

  2. TopCoder SRM 566 Div 1 - Problem 1000 FencingPenguins

    传送门:https://284914869.github.io/AEoj/566.html 题目简述: 平面上有中心在原点,一个点在(r,0)处的正n边形的n个顶点.平面上还有m个企鹅,每个企鹅有一个 ...

  3. TopCoder SRM 561 Div 1 - Problem 1000 Orienteering

    传送门:https://284914869.github.io/AEoj/561.html 题目简述: 题外话: 刚开始看题没看到|C|<=300.以为|C|^2能做,码了好久,但始终解决不了一 ...

  4. TopCoder SRM 582 Div 1 - Problem 1000 SemiPerfectPower

    首先我们可以把答案差分,那么我们只需要求出\(1\)~\(x\)范围内的满足条件的数即可. 题目要求的应该是这个东西的个数: \(l \leq a*b^c \leq r(1 \le a < b) ...

  5. TopCoder SRM 559 Div 1 - Problem 900 CircusTents

    传送门:https://284914869.github.io/AEoj/559.html 题目简述: n个实心圆,两两没有交集,在第一个圆上找一个点,使得它到另外一个圆上某个点的最短距离的最小值尽量 ...

  6. TopCoder SRM 667 Div.2题解

    概览: T1 枚举 T2 状压DP T3 DP TopCoder SRM 667 Div.2 T1 解题思路 由于数据范围很小,所以直接枚举所有点,判断是否可行.时间复杂度O(δX × δY),空间复 ...

  7. TopCoder SRM 642 Div.2 1000 --二分+BFS

    题意: 给你一张图,N个点(0~N-1),m条边,国王要从0到N-1,国王携带一个值,当走到一条边权大于此值的边时,要么不走,要么提升该边的边权,提升k个单位花费k^2块钱,国王就带了B块钱,问能携带 ...

  8. TopCoder SRM 596 DIV 1 250

    body { font-family: Monospaced; font-size: 12pt } pre { font-family: Monospaced; font-size: 12pt } P ...

  9. Topcoder SRM 656 (Div.1) 250 RandomPancakeStack - 概率+记忆化搜索

    最近连续三次TC爆零了,,,我的心好痛. 不知怎么想的,这题把题意理解成,第一次选择j,第二次选择i后,只能从1~i-1.i+1~j找,其实还可以从j+1~n中找,只要没有被选中过就行... [题意] ...

随机推荐

  1. 201621123040《Java程序设计》第六周学习总结

    1.本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结 2.书面作业 2.1clone方法 2.1.1在te ...

  2. HTML5文件操作API

    HTML5文件操作API       一.文件操作API 在之前我们操作本地文件都是使用flash.silverlight或者第三方的activeX插件等技术,由于使用了这些技术后就很难进行跨平台.或 ...

  3. OpenShift实战(一):OpenShift高级安装

    1.1 服务器基本信息 本次安装采用一个master.5个node.3个etcd,node节点两块硬盘,60G磁盘用于docker storage,xxx改为自己的域名或主机名. 节点 功能 IP 内 ...

  4. JAVA类的方法调用和变量(全套)

    一.类的分类: 1.普通类 2.抽象类(含有抽象方法的类) 3.静态类(不需要实例化,就可以使用的类) 二.方法的分类: 1.私有方法(只有类的内部才可以访问的方法) 2.保护方法(只有类的内部和该该 ...

  5. JAVA_SE基础——29.构造函数

    黑马程序员入学Blog... jvm创建Java对象时候需要调用构造器,默认是不带参数的.在构造器中,你可以让jvm帮你初始化一些参数或者执行一系列的动作. 它是对象创建中执行的函数,及第一个被执行的 ...

  6. JS实现页面内跳转

    使用js($.ajax中)实现页面内跳转(即:描点平滑跳转)的方法(aa为跳转目的标签的id): 在网络上有很多资料所说的:animate方法我试了并不好使,不知道是啥原因,欢迎大家指正,附上网络方法 ...

  7. ELK学习总结(1-1)ELK是什么

    1.elk 是什么 ? Elastic Stack(旧称ELK Stack),是一种能够从任意数据源抽取数据,并实时对数据进行搜索.分析和可视化展现的数据分析框架.(hadoop同一个开发人员) ja ...

  8. NOPI实现导入导出泛型List,支持自定义列

    概述 业务上需要自定义列的Excel的导入导出,在网上看了好多资料,很多都是有Bug而且都是支持Excel和DataTable的转换,所以自己总结了一下,应用.NET平台上的NPOI封装了支持自定义列 ...

  9. JavaScript实现接口的三种经典方式

    /* 接口:提供一种说明一个对象应该有哪些方法的手段 js中有三种方式实现接口: 1 注释描述接口 2 属性检测接口 3 鸭式辨型接口 */ /* 1 注释描述接口: 不推荐 优点: 利用注解,给出参 ...

  10. python与mongodb的交互 增删改差

    首先引入包: pip install pymongo需要用到如下对象: MongoClient对象:用于与MongoDB服务器建立连接 client=MongoClient('主机ip',端口) Da ...