POJ 3422 最小费用流

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 1E5 + 10;
const int maxm = 1E6 + 10;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to, next, cap, flow, cost;
};
Edge edge[maxm];
int head[maxn], tol, pre[maxn], dis[maxn], n, k, m, a[55][55], ans;
bool vis[maxn];
void addedge(int u, int v, int cap, int cost)
{
    edge[tol].to = v;
    edge[tol].cap = cap;
    edge[tol].cost = cost;
    edge[tol].flow = 0;
    edge[tol].next = head[u];
    head[u] = tol++;
    edge[tol].to = u;
    edge[tol].cap = 0;
    edge[tol].cost = -cost;
    edge[tol].flow = 0;
    edge[tol].next = head[v];
    head[v] = tol++;
}
bool spfa(int s, int t)
{
    queue<int>q;
    memset(dis, INF, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    dis[s] = 0;
    vis[s] = true;
    q.push(s);
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        vis[u] = false;
        for (int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost)
            {
                dis[v] = dis[u] + edge[i].cost;
                pre[v] = i;
                if (!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    return (pre[t] == -1 ? false : true);
}
int MinCostMaxFlow(int s, int t, int &cost)
{
    int flow = 0; cost = 0;
    while (spfa(s, t))
    {
        int Min = INF;
        for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])
            Min = min(Min, edge[i].cap - edge[i].flow);
        for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])
        {
            edge[i].flow += Min;
            edge[i ^ 1].flow -= Min;
            cost += edge[i].cost * Min;
        }
        flow += Min;
    }
    return flow;
}
int main(int argc, char const *argv[])
{
    while (~scanf("%d%d", &n, &k))
    {
        tol = 0;
        memset(head, -1, sizeof(head));
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
            {
                scanf("%d", &a[i][j]);
                addedge(n * i + j + 1, n * n + n * i + j + 1, 1, -a[i][j]);
                addedge(n * i + j + 1, n * n + n * i + j + 1, INF, 0);
                if (i < n - 1) addedge(n * n + n * i + j + 1, n * (i + 1) + j + 1, INF, 0);
                if (j < n - 1) addedge(n * n + n * i + j + 1, n * i + j + 1 + 1, INF, 0);
            }
        addedge(0, 1, k, 0);
        addedge(2 * n * n, 2 * n * n + 1, INF, 0);
        MinCostMaxFlow(0, 2 * n * n + 1, ans);
        printf("%d\n", -ans);
    }
    return 0;
}


有一个n*n的矩阵,格子中的元素是费用,KaKa从左上角开始出发要到达右下角,但是他只能向下走或者向右走,且走过的格子赋值为0,可以走K次,问K次后KaKa能获得的最大费用是多少?要获得最大费用,所以假设当前步选择先下走,最终得到的结果可能不是最大值,但根据题意却把走过的格子赋为0了,这就影响了最终结果。所以进行拆点,把每个点拆成两个点,入度点和出度点,本点的入度点连接着本点的出度点,费用为本点格子的值的负值,容量为1(因为当前点的入度点只能由(上边点)/(左边点)的出度点连接,所以容量是1),这样使用流网络就保证了最终的结果不受一些不是最优解的中间过程的影响。而当前点的出度点连接下个点的入度点的费用为0,容量为K,因为可以走K次,所以在走过一次后,费用已经赋为0,容量就变成K-1,谁走进当前格子,对整体的费用已经没有影响了。

再建立一个源点和一个汇点,源点与1点(左上角)相连费用0,容量K,汇点与2*n*n+1点(右下角)相连费用0,容量为K

你可能感兴趣的:(POJ 3422 最小费用流)