ACM/ICPC 之 卡卡的矩阵旅行-最小费用最大流(可做模板)(POJ3422)

  将每个点拆分成原点A与伪点B,A->B有两条单向路(邻接表实现时需要建立一条反向的空边,并保证环路费用和为0),一条残留容量为1,费用为本身的负值(便于计算最短路),另一条残留容量+∞,费用为0(保证可以多次通过该点,但费用只计算一次)。

  另外伪点B与原点右侧与下方的点有一条单向路(邻接表实现需要建立反向空边),残留容量为+∞,费用为0。源点0到点1有一条单向路,残留容量为K(可以通过K次),最后一个点的伪点2*n*n与汇点2*n*n+1有一条单向边,残留容量为K,两条边的费用都为0。

  构图成功后,走一次最小费用最大流即可。

//最小费用最大流问题-拆点
//Time:47Ms     Memory:624K
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define MAX 55
#define MAXN 5005
#define INF 0x3f3f3f3f
struct Edge{
    int u,v,r,w,next;
    Edge(){}
    Edge(int U,int V,int R,int W,int N):u(U),v(V),r(R),w(W),next(N){}
}e[MAXN*8];
int n,k;
int s,t;
int h[MAXN],le;
int m[MAX][MAX];
int pre[MAXN];
int cost[MAXN];
bool vis[MAXN];
void add(int u,int v,int r,int w)
{
    e[le] = Edge(u,v,r,w,h[u]);   h[u] = le++;
    e[le] = Edge(v,u,0,-w,h[v]);   h[v] = le++;
}
void build()
{
    add(s, 1, k, 0);
    add(2*n*n, t, k, 0);
    for(int i = 1; i <= n*n; i++)
    {
        add(i, n*n+i, 1, -m[(i - 1)/n + 1][(i - 1)%n + 1]);
        add(i, n*n+i, k, 0);
        if(i % n)   add(i+n*n, i+1, INF, 0);
        if(i <= n*(n-1))    add(i+n*n, i+n, INF, 0);
    }
}
bool spfa()
{
    memset(pre,-1,sizeof(pre));
    memset(vis,false,sizeof(vis));
    memset(cost,INF,sizeof(cost));
    queue<int> q;
    q.push(s);
    cost[s] = 0;    vis[s] = true;
    while(!q.empty()){
        int cur = q.front();
        q.pop();    vis[cur] = false;
        for(int i = h[cur]; i != -1; i = e[i].next)
        {
            int v = e[i].v;
            if(e[i].r && cost[v] > cost[cur] + e[i].w){
                cost[v] = cost[cur] + e[i].w;
                pre[v] = i;
                if(!vis[v]){
                    vis[v] = true;  q.push(v);
                }
            }
        }
    }
    return cost[t] == INF? false: true;
}
int maxcostflow()
{
    int maxFlow = 0;
    while(spfa()){  //增广路
        int mind = INF;
        for(int i = pre[t]; i != -1; i = pre[e[i].u])
            mind = min(mind, e[i].r);
        for(int i = pre[t]; i != -1; i = pre[e[i].u])
        {
            e[i].r -= mind;
            e[i^1].r += mind;
        }
        maxFlow += mind*cost[t];
    }
    return maxFlow;
}
int main()
{
    //freopen("in.txt", "r", stdin);
    memset(h, -1, sizeof(h));
    scanf("%d%d", &n,&k);
    s = 0; t = 2*n*n+1;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            scanf("%d", &m[i][j]);
    build();
    printf("%d\n", -maxcostflow());
    return 0;
}
时间: 2024-10-28 22:05:20

ACM/ICPC 之 卡卡的矩阵旅行-最小费用最大流(可做模板)(POJ3422)的相关文章

AHU-835 FJ的旅行 【最小费用最大流】

Description 每当西瓜的朋友来西瓜家看他,西瓜总是喜欢带他们逛自己的豪宅.西瓜的豪宅有N幢楼(1<=N<=1000),用1到N的整数编号.1号楼是西瓜豪宅的大门,N号楼是西瓜的储藏室.西瓜的豪宅里总共有M条道路(1<=M<=10000).每条道路连接两栋不同的楼房,道路的长度不超过35000.为了最好地炫耀他的豪宅,西瓜准备从大门出发,经过一些楼房到达储藏室,再经过一些楼房回到自己的大门.他要求他的路径越短越好,但是不能经过任意一条道路多于一次.请你计算这样的一条最短路径

HDU ACM 4494 Teamwork 最小费用最大流

题意:n个工作地,m种工人,工作地0是仓库,其他的都需要修缮,每个地点需要多个工种的工人若干,不同工种不能相互取代.每个工作地有一个开工时间,凑齐所有工人后准时开工,修缮也需要一定时间.一个工人可以在一个地方工作完后再到其他地方,两地直接的距离是欧几里得距离,可以算作时间.最少需要多少工人. 分析:只用费用流.每种工人不能相互替换,没有任何关系.因此对每个工种进行建图求解最小费用累加即可得到最终结果. 超级源点cs是仓库,超级汇点为ct. 一个地点拆成三个点,i.i'.i".k表示工种,对每个点

POJ 3422 Kaka&#39;s Matrix Travels 【最小费用最大流】

题意: 卡卡有一个矩阵,从左上角走到右下角,卡卡每次只能向右或者向下.矩阵里边都是不超过1000的正整数,卡卡走过的元素会变成0,问卡卡可以走k次,问卡卡最多能积累多少和. 思路: 最小费用最大流的题目. 建图自己没想出来,看了大神的建边,把每个点分解成两个点,一个代表进入一个代表出去,然后每个进入和每个出去连边,容量是1价值是这个点的矩阵的数值.然后因为可以不进去,所以起点要和别的矩阵元素的起点建边,终点也要和别的矩阵矩阵元素的起点建边,最后跑下最小费用最大流. 这题最右下角的矩阵元素需要特殊

POJ--3422--Kaka&#39;s Matrix Travels【最小费用最大流+拆点】

链接:http://poj.org/problem?id=3422 卡卡 题意:卡卡的矩阵之旅,有一个n*n的矩阵,卡卡要从左上角走到右下角,每次他只能往右或往下走,卡卡可以走k遍这个矩阵,每个点有一个num值,卡卡走到这里可以获得num点,一个点只能获得一次num值,问卡卡走完k遍后身上num值最大可以是多少? 思路:其实看到这题时没思路,图论书上说了建图的方式,但没有说为什么,我不解,网上搜了一下解题报告,百度了两页,我看到的博客都是写了如何建图,但没有写为什么要这么建..我觉得我真是弱渣,

hdu 1533 Going Home 最小费用最大流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1533 On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need

HDU 4862 Jump (2014-多校1-1002,最小K路径覆盖,最小费用最大流)

题目: http://acm.hdu.edu.cn/showproblem.php?pid=4862 题意: 给你一个n*m的矩阵,填充着0-9的数字,每次能从一个点出发,到它的右边或者下边的点,花费为|x1-x2|+|y1-y2|-1,如果跳跃的起点和终点的数字相同,则获得这个数字的收益,不能走已经走过的点 有K次重新选择起点的机会 如果可以走遍所有点,则输出最大的价值(收益-花费) 否则,输出-1 方法: 最小K路径覆盖,最小费用最大流 建图: 每个点拆为2点:X部和Y部,(a,b)表示流量

hdu 2686 Matrix 最小费用最大流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686 Yifenfei very like play a number game in the n*n Matrix. A positive integer number is put in each area of the Matrix.Every time yifenfei should to do is that choose a detour which frome the top left

hdu 4494 Teamwork 最小费用最大流

Teamwork Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4494 Description Some locations in city A has been destroyed in the fierce battle. So the government decides to send some workers to repair these location

POJ - 2195 Going Home(最小费用最大流)

1.N*M的矩阵中,有k个人和k个房子,每个人分别进入一个房子中,求所有人移动的最小距离. 2.人看成源点,房子看成汇点,求最小费用最大流. 建图-- 人指向房子,容量为1,费用为人到房子的曼哈顿距离. 建立超级源点和超级汇点:超级源点指向人,容量为1,费用为0:超级汇点指向房子,容量为1,费用为0. 求超级源点到超级汇点的最小费用最大流即可. ps:容量为什么都设为1?---有待研究.. 3. 1.Bellman-Ford: #include<iostream> #include<st