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

来源:互联网 发布:淘宝保无忧退货 编辑:程序博客网 时间:2024/05/20 18:46

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 - 汇点]//双向边,注意REstruct 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;}/*992 5 111111111112 5 211111111112 5 201110101012 5 310101021101 5 1009192910 10 1004545654101153132156451256412341564531045231354313256441345411313413243547896416512344686121213541550*/


0 0