题目链接

每层每个位置向下一层这个位置连边,流量为下一层这个位置的\(f\),源点向第一层连,流量第一层每个位置的费用,最后一层向汇点连,流量\(INF\)。

这样就得到了\(P*Q\)条链,不考虑\(D\)的限制的话求最小割就是答案。

现在加入限制。记结论吧,我也不知道什么原理

每个位置从\(i=D+1\)层开始,向他前后左右第\(i-D\)层连边,流量\(INF\)。

然后求出最小割即为答案。

#include <cstdio>
#include <queue>
#include <cstring>
#define INF 2147483647
using namespace std;
const int MAXN = 900010;
const int MAXM = 2000010;
inline int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); }
return s * w;
}
struct Edge{
int next, to, rest;
}e[MAXM];
int s, t, num = 1, n, m, a, b, c, p, q, r, d, f[45][45][45];
int head[MAXN];
inline void Add(int from, int to, int flow){
e[++num] = (Edge){ head[from], to, flow }; head[from] = num;
e[++num] = (Edge){ head[to], from, 0 }; head[to] = num;
}
int level[MAXN], now, sum;
queue <int> Q;
int re(){
memset(level, 0, sizeof level);
while(Q.size()) Q.pop();
Q.push(s); level[s] = 1;
while(Q.size()){
now = Q.front(); Q.pop();
for(int i = head[now]; i; i = e[i].next)
if(e[i].rest && !level[e[i].to]){
level[e[i].to] = level[now] + 1;
Q.push(e[i].to);
}
}
return level[t];
}
int findflow(int u, int flow){
if(!flow || u == t) return flow;
int f = 0, t;
for(int i = head[u]; i; i = e[i].next){
if(e[i].rest && level[e[i].to] == level[u] + 1){
f += (t = findflow(e[i].to, min(flow - f, e[i].rest)));
e[i].rest -= t; e[i ^ 1].rest += t;
}
}
if(!f) level[u] = 0;
return f;
}
int dinic(){
int ans = 0;
while(re())
ans += findflow(s, INF);
return ans;
}
int id(int k, int i, int j){
if(!k) return s;
return (k - 1) * (p * q) + (i - 1) * q + j;
}
int L[] = {233, -1, 1, 0, 0}, R[] = {666, 0, 0, -1, 1};
int main(){
p = read(); q = read(); r = read(); d = read();
s = 899999; t = 900000;
for(int i = 1; i <= p; ++i)
for(int j = 1; j <= q; ++j)
Add(id(r, i, j), t, INF);
for(int k = 1; k <= r; ++k)
for(int i = 1; i <= p; ++i)
for(int j = 1; j <= q; ++j)
Add(id(k - 1, i, j), id(k, i, j), read());
for(int i = 1; i <= p; ++i)
for(int j = 1; j <= q; ++j)
for(int k = 1; k <= 4; ++k){
int x = i + L[k], y = j + R[k];
if(!x || !y || x > p || y > q) continue;
for(int o = d + 1; o <= r; ++o)
Add(id(o, i, j), id(o - d, x, y), INF);
}
printf("%d\n", dinic());
return 0;
}

最新文章

  1. Git私钥openssh格式转ppk
  2. 反射 + 抽象工厂模式切换DB数据源(附Demo)
  3. 【转】图像灰度化方法总结及其VC实现
  4. 四则运算GUI设计
  5. css,html命名规则
  6. java functional syntax overview
  7. Java学习之IO之File类一
  8. 开发Nagios监控passwd文件插件
  9. HDU 5556 最大独立集
  10. 201521123042 《Java程序设计》第4周学习总结
  11. Oracle的坑,你是否踩过?----安装篇
  12. Mac App开发
  13. 我所知道的几种display:table-cell的应用
  14. Debug的使用
  15. visual studio运行时库MT、MTd、MD、MDd 的区别
  16. 【转】__ATTRIBUTE__ 你知多少
  17. js冒泡法和数组转换成字符串示例代码
  18. php实现base64图片上传方式实例代码
  19. array_unique() 函数移除数组中的重复的值
  20. 孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘

热门文章

  1. Markdown github 风格语法
  2. JS高级 2
  3. UML之Enterprise Architect使用
  4. 【beta】Scrum站立会议第5次....11.7
  5. 【前端学习笔记03】JavaScript对象相关方法及封装
  6. 【三】shiro入门 之 Realm
  7. Netsh命令-网络禁用开启
  8. Linux内核设计与实现第六周读书笔记
  9. 51nod1967 路径定向(欧拉回路+结论题)
  10. day2-python基础