首页 > 代码库 > HDU 3376 && 2686 方格取数 最大和 费用流裸题

HDU 3376 && 2686 方格取数 最大和 费用流裸题

题意:

1、一个人从[1,1] ->[n,n] ->[1,1] 

2、只能走最短路

3、走过的点不能再走

问最大和。

对每个点拆点限流为1即可满足3.

费用流流量为2满足1

最大费用流,先给图取负,结果再取负,满足2

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
#include <queue>
#include <set>
#include <algorithm>
#include <stdlib.h>

#define N 605*605*2
#define M N*2
#define inf 1<<29
#define ll int

using namespace std;

//双向边,注意RE
//注意 点标必须是 [0 - 汇点]
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 Mincost(ll s,ll t){//返回最小费用
    ll flow = 0, cost = 0;
    while(BellmanFord(s, t, flow, cost));
    return cost;
}
void init(){memset(head,-1,sizeof head); edgenum = 0;}
ll n;
ll Hash(ll x,ll y){return (x-1)*n+y;}
ll Hash2(ll x,ll y){return n*n+(x-1)*n+y;}
ll mp[605][605];
int main(){
    ll i, j, u, v, cost;
    while(~scanf("%d",&n)){
        init();
        for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%d",&mp[i][j]);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                add(Hash(i,j),Hash2(i,j),1,-mp[i][j]);
                u = Hash2(i,j);
                if(i!=n)
                {
                    v = Hash(i+1,j);
                    add(u,v,3,0);
                }
                if(j!=n)
                {
                    v = Hash(i,j+1);
                    add(u,v,3,0);
                }
            }
        }
		add(Hash(1,1), Hash2(1,1), 1, 0);
		add(Hash(n,n), Hash2(n,n), 1, 0);
        printf("%d\n",-Mincost(Hash(1,1), Hash2(n,n)));
    }
    return 0;
}