POJ 2135 Farm Tour && HDU 2686 Matrix && HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,近期总是被虐到没脾气。

来回最短路问题貌似也能够用DP来搞。只是拿费用流还是非常方便的。

能够转化成求满流为2 的最小花费。一般做法为拆点,对于 i 拆为2*i 和 2*i+1。然后连一条流量为1(花费依据题意来定) 的边来控制每一个点仅仅能通过一次。

额外加入source和sink来控制满流为2。

代码都雷同,以HDU3376为例。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 6000007

using namespace std;

const int EDGE = 6000000,POINT = 730000;

struct E
{
    int Max,cost,v,next;
}edge[EDGE];

int head[POINT];

int Top;

void Link(int u,int v,int w,int cost)
{
    edge[Top].v = v;
    edge[Top].Max = w;
    edge[Top].cost = cost;
    edge[Top].next = head[u];
    head[u] = Top++;
}

int Map[610][610];

int dis[POINT],cur[POINT],flow[POINT];
bool mark[POINT];

void Updata(int site,int flow,int &cost)
{
    for(;cur[site] != -1; site = edge[cur[site]^1].v)
    {
        edge[cur[site]].Max -= flow;
        edge[cur[site]^1].Max += flow;
        cost += edge[cur[site]].cost * flow;
    }
}

queue<int> q;

int spfa(int S,int T,int &cost)
{
    memset(mark,false,sizeof(mark));
    memset(dis,INF,sizeof(dis));

    cur[S] = -1,dis[S] = 0,flow[S] = INF;

    q.push(S);

    int f,t;

    while(q.empty() == false)
    {
        f = q.front();
        q.pop();
        mark[f] = false;

        for(int p = head[f];p != -1; p = edge[p].next)
        {
            t = edge[p].v;
            if(edge[p].Max && dis[t] > dis[f] + edge[p].cost)
            {
                dis[t] = dis[f] + edge[p].cost;
                cur[t] = p;
                flow[t] = min(flow[f],edge[p].Max);

                if(mark[t] == false)
                {
                    mark[t] = true;
                    q.push(t);
                }
            }
        }
    }

    if(dis[T] == INF)
        return 0;
    Updata(T,flow[T],cost);
    return flow[T];
}

int Cal_Max_Flow_Min_Cost(int S,int T,int n)
{
    int temp,flow = 0,cost = 0;

    do
    {
        temp = spfa(S,T,cost);
        flow += temp;
    }while(temp);
    return cost;
}

inline int Cal(int x,int y,int n)
{
   return ((x-1)*n+y)*2-1;
}

int main()
{
    int n;
    int i,j;

    while(scanf("%d",&n) != EOF)
    {
        memset(head,-1,sizeof(head));
        Top = 0;

        for(i = 1;i <= n; ++i)
        {
            for(j = 1;j <= n; ++j)
            {
                scanf("%d",&Map[i][j]);
                if(i == j && (i == 1 || i == n))
                    Link(Cal(i,j,n),Cal(i,j,n)+1,2,-Map[i][j]);
                else
                    Link(Cal(i,j,n),Cal(i,j,n)+1,1,-Map[i][j]);
                Link(Cal(i,j,n)+1,Cal(i,j,n),0,Map[i][j]);
            }
        }

        for(i = 1;i <= n; ++i)
        {
            for(j = 1;j <= n; ++j)
            {
                if(j < n)
                {
                    Link(Cal(i,j,n)+1,Cal(i,j+1,n),1,0);
                    Link(Cal(i,j+1,n),Cal(i,j,n)+1,0,0);
                }
                if(i < n)
                {
                    Link(Cal(i,j,n)+1,Cal(i+1,j,n),1,0);
                    Link(Cal(i+1,j,n),Cal(i,j,n)+1,0,0);
                }
            }
        }

        printf("%d\n",-Cal_Max_Flow_Min_Cost(1,n*n*2,n*n*2) - Map[1][1] - Map[n][n]);
    }
    return 0;
}

posted @ 2016-01-03 20:16  hrhguanli  阅读(146)  评论(0编辑  收藏  举报