不管是最大流還是費用流,模板一般都不會出什麼問題,一般錯就錯在建圖……
這也是一道裸的套費用流模板的題,不得不說,費用流代碼量真是大,初始化什麼的完成基本就快100行代碼了。
費用流的基本思想是多次最短路,所以在MCMF函數裏會看到while(spfa(st, ed))這麼個東西。
先貼代碼後分析:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 555;
const int maxm = 55555;
const int inf = 1 << 30;
struct node
{
int to, next, c, f;
}edge[maxm * 10];
int head[maxn];
int src, des, r, c, n, k, sm;
int dis[maxn], load[maxn], p[maxn];
bool vis[maxn][maxn];
bool flag[maxn];
int a[20][20];
int xx[8] = {1, 2, 2, 1, -1, -2, -2, -1};
int yy[8] = {-2, -1, 1, 2, -2, -1, 1, 2};
bool isok(int x, int y)
{
return (x >= 0 && x < r && y >= 0 && y < c);
}
void add_edge(int u, int v, int c, int f)
{
edge[sm].to = v;
edge[sm].c = c;
edge[sm].f = f;
edge[sm].next = head[u];
head[u] = sm ++;
edge[sm].to = u;
edge[sm].c = 0;
edge[sm].f = -f;
edge[sm].next = head[v];
head[v] = sm ++;
}
bool spfa(int st, int ed)
{
int que[maxn * 10], qout, qin;
memset(flag, false, sizeof(flag));
memset(load, -1, sizeof(load));
memset(p, -1, sizeof(p));
for(int i = 0; i <= des + 1; i ++)
dis[i] = inf;
qin = qout = 0;
que[qin ++] = st;
dis[st] = 0;
flag[st] = true;
while(qin != qout)
{
int e = que[qout ++];
flag[e] =false;
for(int i = head[e]; i != -1; i = edge[i].next)
{
if(edge[i].c)
{
int ne = edge[i].to;
if(dis[ne] - dis[e] > edge[i].f)
{
dis[ne] = edge[i].f + dis[e];
p[ne] = e;
load[ne] = i;
if(!flag[ne])
{
flag[ne] = true;
que[qin ++] = ne;
}
}
}
}
}
if(dis[ed] == inf)
return false;
return true;
}
int MCMF(int st, int ed)
{
int u, mn;
int ans_f = 0, ans_c = 0;
while(spfa(st, ed))
{
u = ed;
mn = inf;
while(p[u] != -1)
{
mn = min(edge[load[u]].c, mn);
u = p[u];
}
u = ed;
while(p[u] != -1)
{
edge[load[u]].c -= mn;
edge[load[u]^1].c += mn;
u = p[u];
}
ans_c += dis[ed] * mn;
ans_f += mn;
}
if(ans_f != k)
return -1;
return ans_c;
}
int main()
{
while(scanf("%d%d%d%d", &r, &c, &n, &k) != EOF)
{
int i, j, type;
for(i = 0; i < r; i ++)
for(j = 0; j < c; j ++)
scanf("%d", &a[i][j]);
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
sm = 0;
src = r * c + 1, des = r * c + 2;
add_edge(src, r * c, k, 0);
for(int u = 0; u < n; u ++)
{
scanf("%d%d%d", &type, &i, &j);
i --, j --;
int tmp = i * c + j;
add_edge(r * c, tmp, 1, 0);
for(int no = 0; no < 8; no ++)
{
int px = xx[no] + i;
int py = yy[no] + j;
if(isok(px, py))
{
int tmp2 = px * c + py;
if(type == 1)
add_edge(tmp, tmp2, 1, a[i][j] * a[px][py]);
if(type == 2)
add_edge(tmp, tmp2, 1, a[i][j] + a[px][py]);
if(type == 3)
add_edge(tmp, tmp2, 1, max(a[i][j], a[px][py]));
vis[px][py] = true;
}
}
}
for(i = 0; i < r * c; i ++)
if(vis[i / c][i % c])
add_edge(i, des, 1, 0);
int ans = MCMF(src, des);
printf("%d\n", ans);
}
}
for(i = 0; i < r * c; i ++)
if(vis[i / c][i % c])
add_edge(i, des, 1, 0);
之前一直沒調出來的程序裏是沒有if判斷的,結果就一直不對。後來突然想到,如果對每個點都向超級終點連邊,而且容量是1,費用是0的話,最後就會發生ans = 0的情況,因爲好多不相關的點都被連了進去,他們本來的費用是0。
明天繼續網絡流 + 數據結構。