题意
地图是个矩形的网格。
可以花费一定金钱在一些格子投资。
被投资的格子或者四连通的格子都被投资的话,我就可以获得该格子的收益。
利益最大化是作为商人的基本准则,但这是计算机的任务,拜托您了。
数据
第一行两个数 n,m(n,m ≤ 20),表示矩形的长和宽。
接下来 n 行,每行是 m 个字符组成的字符串,描述投资的花费。
接下来 n 行,每行是 m 个字符组成的字符串,表示该格子的收益。
花费和收益按照一种奇葩的方式给出:
字符 数
‘0’ -’ 9’ 0-9
‘a’ -’ z’ 10-35
‘A’ -’ Z’ 36-61
Analysis
神奇的网络流二元关系建图(好像是裸题,然而我太弱了,并不会)。考虑一个格子有两个限制,但需要另外的点来限制当前点,那么需要黑白点染色。将一个点拆成
x,y
x
,
y
.
x−>y
x
−
>
y
连一条流量为
vali,j
v
a
l
i
,
j
的边
若为白点,
S−>x
S
−
>
x
连一条流量为
costi,j
c
o
s
t
i
,
j
的边
若为黑点,
x−>T
x
−
>
T
如上。
然后白向黑如下连边
x−>x1
x
−
>
x
1
连一条
inf
i
n
f
,
y−>y1
y
−
>
y
1
连一条
inf
i
n
f
。
这样图就建好了,用总收益减最小割得到答案。证明一下正确性,要保留
cost
c
o
s
t
的边,只有割掉
val
v
a
l
或者将相连黑点的
cost
c
o
s
t
割掉,满足上述限制。
Code
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
# define id(i,j) ((i - 1) * m + j)
const int N = 20 + 5;
const int M = 1e4 + 5;
const int inf = 0x3f3f3f3f;
int c[N][N],val[N][N],q[M],dis[M],dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
int to[M << 1],nx[M << 1],flow[M << 1],st[M];
int n,m,ret,ans,S,T,tot = 1;
void add(int u,int v,int w)
{
to[++tot] = v,nx[tot] = st[u],flow[tot] = w,st[u] = tot;
to[++tot] = u,nx[tot] = st[v],flow[tot] = 0,st[v] = tot;
}
inline bool bfs()
{
memset(dis,0xff,sizeof(dis));
int h = 1,t = 0; q[++t] = S,dis[S] = 0;
while (h <= t)
{
int x = q[h++];
for (int i = st[x] ; i ; i = nx[i])
{
if (~dis[to[i]] || !flow[i]) continue;
dis[to[i]] = dis[x] + 1,q[++t] = to[i];
}
}
return dis[T] != -1;
}
inline int dfs(int x,int mx)
{
if (x == T) return mx;
int ret = 0,now;
for (int i = st[x] ; i ; i = nx[i])
if (dis[to[i]] == dis[x] + 1 && flow[i] && (now = dfs(to[i],min(mx,flow[i]))))
{
flow[i] -= now,mx -= now;
flow[i ^ 1] += now,ret += now;
if (!mx) break;
}
if (!ret) dis[x] = -1;
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i = 1 ; i <= n ; ++i)
for (int j = 1 ; j <= m ; ++j)
{
char ch; scanf(" %c",&ch);
if (ch >= '0' && ch <= '9') c[i][j] = ch - '0';
if (ch >= 'a' && ch <= 'z') c[i][j] = ch - 'a' + 10;
if (ch >= 'A' && ch <= 'Z') c[i][j] = ch - 'A' + 36;
}
for (int i = 1 ; i <= n ; ++i)
for (int j = 1 ; j <= m ; ++j)
{
char ch; scanf(" %c",&ch);
if (ch >= '0' && ch <= '9') val[i][j] = ch - '0';
if (ch >= 'a' && ch <= 'z') val[i][j] = ch - 'a' + 10;
if (ch >= 'A' && ch <= 'Z') val[i][j] = ch - 'A' + 36;
ret += val[i][j];
}
S = 0,T = n * m * 2 + 1;
for (int i = 1 ; i <= n ; ++i)
for (int j = 1 ; j <= m ; ++j)
{
if ((i + j) & 1)
{
add(id(i,j) + n * m,T,c[i][j]),add(id(i,j),id(i,j) + n * m,val[i][j]);
continue;
}
add(S,id(i,j),c[i][j]),add(id(i,j),id(i,j) + n * m,val[i][j]);
for (int k = 0 ; k < 4 ; ++k)
{
int x = i + dir[k][0],y = j + dir[k][1];
if (x < 1 || x > n || y < 1 || y > m) continue;
add(id(i,j),id(x,y),inf),add(id(i,j) + n * m,id(x,y) + n * m,inf);
}
}
while (bfs()) ans += dfs(S,inf);
printf("%d\n",ret - ans);
return 0;
}