我真的好烦这个addEdge啊,每次看到这个就晕
没怎么看懂,不想看
题意:对于N*N的数组,给一个k,从(1,1)走到(N,N),走k次,走到每个点权值加上当前这个点的权值,之后这个点权值为0,求最大权值
对点进行拆分建图,一个点拆为两个点a和b,在a和b之间建一条花费为输入值容量为1的边,然后再建一条花费为0容量为k-1的边,对b点对于其右边和下边都建立一条容量为k花费为0的边,加入超级源点和汇点,花费为0容量为k,由此套模板就可以了
#include<iostream>
#include<string.h>
#include<stdio.h>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int nMax = 5005;
const int eMax = 20050;
struct
{
int v, cap, cost, next, re;
} edge[eMax];
int n, ans;
int k, edgeHead[nMax];
int que[nMax], pre[nMax], dis[nMax];
bool vis[nMax];
void addEdge(int u, int v, int ca, int co)
{
edge[k].v = v;
edge[k].cap = ca;
edge[k].cost = co;
edge[k].next = edgeHead[u];
edge[k].re = k + 1;
edgeHead[u] = k ++;
edge[k].v = u;
edge[k].cap = 0;
edge[k].cost = -co;
edge[k].next = edgeHead[v];
edge[k].re = k - 1;
edgeHead[v] = k ++;
}
bool spfa()
{
int i, head = 0, tail = 1;
//一开始用堆栈,用了980多MS,囧...
for(i = 0; i <= n; i ++)
{
dis[i] = -1;
vis[i] = false;
}
dis[0] = 0;
que[0] = 0;
vis[0] = true;
while(head != tail)
{
int u = que[head];
for(i = edgeHead[u]; i != 0; i = edge[i].next)
{
int v = edge[i].v;
if(edge[i].cap && dis[v] < dis[u] + edge[i].cost)
{
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v])
{
vis[v] = true;
que[tail ++] = v;
if(tail == nMax) tail = 0;
}
}
}
vis[u] = false;
head ++;
if(head == nMax) head = 0;
}
if(dis[n] <= 0) return false;
return true;
}
void end()
{
int u, p;
for(u = n; u != 0; u = edge[edge[p].re].v)
{
p= pre[u];
edge[p].cap -= 1;
edge[edge[p].re].cap += 1;
ans += edge[p].cost;
}
}
int main()
{
int N, K, map[52][52], i, j;
scanf("%d%d", &N, &K);
for(i = 1; i <= N; i ++)
for(j = 1; j <= N; j ++)
scanf("%d", &map[i][j]);
for(k = i = 1; i <= N; i ++)
for(j = 1; j <= N; j ++)
{
int a = (i-1)*N + j;
int b = a + N*N;
addEdge(a, b, 1, map[i][j]);
//拆点,连2条边。
addEdge(a, b, K, 0);
if(i < N) addEdge(b, a+N, K, 0);
// 向下的点连边
if(j < N) addEdge(b, a+1, K, 0);
// 向右的点连边
}
n = 2*N*N + 1;
addEdge(0, 1, K, 0);
// 连源点的边。
addEdge(2*N*N, n, K, 0);
// 连汇点的边。
ans = 0;
while(spfa())
end();
printf("%d\n", ans);
return 0;
}