HDU 4862 Jump 最小k路径覆盖 费用流

gg。。。

题意:

给定n*m的矩阵

选<=k个起点

每个起点可以向右或向下跳任意步

花费是2点间的曼哈顿距离

若2个格子的数字一样

则赚取格子上的数字的价值

问:遍历整个图的最小花费

若不能遍历则输出-1

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
#include <queue>
#include <set>
#include <algorithm>
#include <stdlib.h>
using namespace std;
#define ll int
#define N 220
#define M 12345
#define inf (1<<29)
//注意 点标必须是 [0 - 汇点]
//双向边,注意RE
struct Edge{
    ll from, to, flow, cap, nex, cost;
}edge[M*2];
ll head[N], edgenum;
void add(ll u,ll v,ll cap,ll cost){//网络流要加反向弧
    Edge E={u, v, 0, cap, head[u], cost};
    edge[edgenum]=E;
    head[u]=edgenum++;
    Edge E2={v, u, 0, 0, head[v], -cost}; //这里的cap若是单向边要为0
    edge[edgenum]=E2;
    head[v]=edgenum++;
}
ll D[N], P[N], A[N];
bool inq[N];
bool BellmanFord(ll s, ll t, ll &flow, ll &cost){
    for(ll i=0;i<=t;i++) D[i]= inf;
    memset(inq, 0, sizeof(inq));
    D[s]=0;  inq[s]=1; P[s]=0; A[s]=inf;
    queue<ll> Q;
    Q.push( s );
    while( !Q.empty()){
        ll u = Q.front(); Q.pop();
        inq[u]=0;
        for(ll i=head[u]; i!=-1; i=edge[i].nex){
            Edge &E = edge[i];
            if(E.cap > E.flow && D[E.to] > D[u] +E.cost){
                D[E.to] = D[u] + E.cost ;
                P[E.to] = i;
                A[E.to] = min(A[u], E.cap - E.flow);
                if(!inq[E.to]) Q.push(E.to) , inq[E.to] = 1;
            }
        }
    }
    if(D[t] == inf) return false;
    flow += A[t];
    cost += D[t] * A[t];
    ll u = t;
    while(u != s){
        edge[P[u]].flow += A[t];
        edge[P[u]^1].flow -= A[t];
        u = edge[P[u]].from;
    }
    return true;
}
ll flow;
ll Mincost(ll s,ll t){//返回最小费用
    flow = 0 ; ll cost = 0;
    while(BellmanFord(s, t, flow, cost));
    return cost;
}
void init(){memset(head,-1,sizeof head); edgenum = 0;}
ll n, m, k;
ll Hash1(ll x, ll y){ return (x-1)*m+y;}
ll Hash2(ll x, ll y){ return n*m + (x-1)*m+y; }
char s[20];
ll mp[20][20];
int main(){
    int T, i, j, g, Cas = 1; scanf("%d",&T);
    while(T--){
        cin>>n>>m>>k;
        for(i = 1; i <= n; i++)
        {
            scanf("%s",s+1);
            for(j = 1; j<=m; j++)
                mp[i][j] = s[j] - '0';
        }
        printf("Case %d : ", Cas++);
        init();
    ll i, j, g;
    ll from = 0, to = Hash2(n,m)+10, jiji = to-2;
    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= m; j++)
        {
            add(from, Hash1(i,j), 1, 0);
            add(Hash2(i,j), to, 1, 0);
            add(jiji, Hash2(i,j), 1, 0);
            for(g = j+1; g <= m; g++)
            {
                ll cos = g - j - 1;
                if(mp[i][j] == mp[i][g]) cos -= mp[i][j];
                add(Hash1(i,j), Hash2(i, g), 1, cos);
            }
            for(g = i+1; g <= n; g++)
            {
                ll cos = g - i - 1;
                if(mp[i][j] == mp[g][j]) cos -= mp[i][j];
                add(Hash1(i,j), Hash2(g, j), 1, cos);
            }
        }
    }
    add(from, jiji, k, 0);
    ll ans = - Mincost(from, to);
    if(flow != n*m)
        puts("-1");
    else
        cout<< ans << endl;
    }
    return 0;
}
/*
99
2 5 1
11111
11111

2 5 2
11111
11111

2 5 2
01110
10101

2 5 3
10101
02110

1 5 100
91929

10 10 100
4545654101
1531321564
5125641234
1564531045
2313543132
5644134541
1313413243
5478964165
1234468612
1213541550

*/

HDU 4862 Jump 最小k路径覆盖 费用流,布布扣,bubuko.com

时间: 2024-08-25 01:01:04

HDU 4862 Jump 最小k路径覆盖 费用流的相关文章

HDU 4862 Jump(最大k路径覆盖 费用流)(待续)

题意:一个n*m的矩阵,需要遍历所有点,从起点出发每次只可向右或向下跳,若到达位置的数字与上一步的数字相同,则获得该数字大小的能量: 否则消耗能量:哈密顿距离减1:求可获得的最大能量: 思路:网络流之最大k路径覆盖. 源点向n*m各点建流量为1,费用为0的边: n*m各点向汇点建流量为1,费用为0的边: 新增一个起点: 源点向起点建流量为k,费用为0的边:起点向各点建流量1,费用为0的边: n*m各点间建边: 建好图后跑最小费用最大流,如果满流则存在解,否则不存在:最小费用的相反数就是所能够获得

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 4862 Jump (最小K路径覆盖)

HDU 4862 Jump 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4862 题意:给定一个N*M的矩阵,矩阵里面为0~9的数字.现在规定从一个点可以跳到它正下方和正右方的点,花费的费用为曼哈顿距离 - 1.如果在跳的过程中,两个点的数字相同,那么将得到该点的数字.规定可以从任意点开始跳,每个点只能经过1次.最多可以选择K个点来作为起点进行跳跃.问能否经过所有的点,如果可以,那么花费的费用是多少. 思路: 如果是最小路径覆盖,那么很容易构造图.但

HDU 4862 Jump(最小K路径覆盖)

输入一个n×m网格图,每个结点的值为0-9,可以从任意点出发不超过k次,走完每个点且仅访问每个结点一次,问最终的能量最大值.不可全部走完的情况输出-1. 初始能量为0. 而结点(x,y)可以跳跃到结点(x,y+dy)或(x+dx,y).消耗能量为跳跃前后结点的曼哈顿距离 - 1 .若跳跃前后的结点的值相等,能量加上那个值. 具体建图可以参考这里http://blog.sina.com.cn/s/blog_6bddecdc0102uy9g.html 最小K路径覆盖其实在之前是见过的打过的,不过这次

hdu 4862 KM算法 最小K路径覆盖的模型

http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过所有的点一次并且仅仅一次, 建图是问题: 我自己最初就把n*m 个点分别放入X集合以及Y集合,再求最优匹配,然后连样例都过不了,而且其实当时解释不了什么情况下不能得到结果,因为k此这个条件相当于没用上... 建图方法: 1.X集合和Y集合都放入n*m+k个点,X中前n*m个点和Y中前n*m个点之间,如果格子里的值相等,权就是(收益-耗费),不等就是(-耗费),因为要的是最大收益

HDU 4862 JUMP 最小费用最大流

2014 多校的B题,由于我不怎么搞图论,当时碰到这个题目,我怎么想都没往网络流方面弄,不过网络流真的是个好东西,对于状态多变,无法用动规或者数据结构来很好表示的时候,非常有用 这个题目要求每个点一定要访问到,并且每次访问的是没访问过的点,跳跃的方向为向右或者向下. 建图的时候,分成二分图,从一个超级源点向x部分建cap为1 cost为0的点,对所以可到达的点从x到y建cap为1,cost根据题目算出来,不过要算负值,因为我们要求得实际是最大费用,最后对结果求相反数即可.所有y部分的点对超级汇点

HDU 4862 Jump(更多的联合培训学校1)(最小费用最大流)

职务地址:pid=4862">HDU4862 最小费用流做的还是太少. 建图想不出来. . . 直接引用官方题解的话吧... 最小K路径覆盖的模型.用费用流或者KM算法解决,构造二部图,X部有N*M个节点.源点向X部每一个节点连一条边,流量1,费用0,Y部有N*M个节点,每一个节点向汇点连一条边.流量1,费用0.假设X部的节点x能够在一步之内到达Y部的节点y,那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量.流量1,再在X部添加一个新的节点,表示能够从随意节点出发K

HDU 4862 Jump(多校联合训练1)(最小费用最大流)

题目地址:HDU4862 最小费用流做的还是太少.建图想不出来... 直接引用官方题解的话吧... 最小K路径覆盖的模型,用费用流或者KM算法解决,构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,流量1,费用0,Y部有N*M个节点,每个节点向汇点连一条边,流量1,费用0,如果X部的节点x可以在一步之内到达Y部的节点y,那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量,流量1,再在X部增加一个新的节点,表示可以从任意节点出发K次,源点向其连边,费用0,流量K,这个点向

HDU 4862 Jump 费用流

又是一个看了题解以后还坑了一天的题…… 结果最后发现是抄代码的时候少写了一个负号. 题意: 有一个n*m的网格,其中每个格子上都有0~9的数字.现在你可以玩K次游戏. 一次游戏是这样定义的: 你可以选任意之前没有走过的格子作为起点.然后走任意步,其中每一步你可以向右或者向下走任意格.假如从(x1, y1)走到(x2, y2)需要花费能量|x1-x2|+|y1-y2|-1,如果这一步和上一步格子的数字相同,那么可以获得格子上相应数字的能量.能量可以为负值. 问你,在K次以内走完所以格子最多能得到多