hdu 4862 Jump 最小费用流

之前也是看的解题报告写的,所以写的不好。现在回头看看,其实很简单。

这篇我只作为笔记使用

14多校赛第一场题解

#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;  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值