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

POJ 2135 Farm Tour && HDU 2686 Matrix && HDU 3376 Matrix Again 费用流求来回最短路,布布扣,bubuko.com

时间: 2024-10-13 23:22:04

POJ 2135 Farm Tour && HDU 2686 Matrix && HDU 3376 Matrix Again 费用流求来回最短路的相关文章

POJ 2135 Farm Tour(费用流)

POJ 2135 Farm Tour 题目链接 题意:给定一个无向图,边有权值,求从1到n再从n到1的最短路 思路:费用流,连边容量为1(注意是无向图),然后源点和1连容量2,n和汇点连容量是2 代码: #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; const int

poj 2135 Farm Tour 【无向图最小费用最大流】

题目:poj 2135 Farm Tour 题意:给出一个无向图,问从 1 点到 n 点然后又回到一点总共的最短路. 分析:这个题目不读仔细的话可能会当做最短路来做,最短路求出来的不一定是最优的,他是两条分别最短,但不一定是和最短. 我们可以用费用流来很轻易的解决,建边容量为1,费用为边权,然后源点s连 1 ,费用0 ,容量 2 ,n点连接汇点,容量2,费用0,,就可以了. 注意这个题目是无向图,所以要建双向边. AC代码: #include <iostream> #include <a

POJ 2135 Farm Tour (dinic算法,网络流)

构图方法: 注意题目中的边为无向边.新建源点s 和 汇点t 每两条道路连一条容量为1,费用为w的边.s到1连一条容量为1,费用为0 的边,n到 t 连一条容量为1,费用为0 的边,求最大流. #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <queue> #include

poj 2135 Farm Tour (最小费用最大流模板)

网络流的费用: 在实际应用中,与网络流有关的问题,不仅涉及流量,而且还有费用的因素.网络的每一条边(v,w)除了给定容量cap(v,w)外,还定义了一个单位流量费用cost(v,w) 最小费用最大流问题 给定网络G,要求G的一个最大用流flow,使流的总费用最小. 求解MCMF问题的算法: 最小费用最大流最常用和基本的算法我们可以称它为最小费用路算法,其思想与求最大流的增广路算法类似,不断在残流网络中寻找从源s到汇t的最小费用路,即残流网络中从s到t的以费用为权的最短路,然后沿最小费用路增流,直

POJ 2135.Farm Tour 最小费用流

Farm Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17307   Accepted: 6687 Description When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of

POJ 2135 Farm Tour

Farm Tour Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 213564-bit integer IO format: %lld      Java class name: Main When FJ's friends visit him on the farm, he likes to show them around. His farm comprise

网络流(最小费用最大流):POJ 2135 Farm Tour

Farm Tour Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 2135 64-bit integer IO format: %lld      Java class name: Main When FJ's friends visit him on the farm, he likes to show them around. His farm compris

poj 2135 Farm Tour 最小费用流入门模板

题意: 求点1到点n再从点n回点1不经过同一条路的最短路. 分析: 建图容易,给一组针对求两次最短路的数据: 4 5 1 2 1 1 3 100 2 4 100 2 3 1 3 4 1 接下来上最小费用流的模板就好. 代码: //poj 2135 //sep9 #include <iostream> #include <queue> using namespace std; const int maxN=2048; const int maxM=20024; struct Edge

POJ 2135 Farm Tour(网络流之费用流)

题目地址:POJ 2135 来回走一遍可以看成从源点到汇点走两遍.将每个点的流量设为1,就可以保证每条边不重复.然后跑一次费用流就行了.当流量到了2之后停止,输出此时的费用. #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <qu