POJ 2135 Farm Tour(费用流)

FJ的农场包含N个字段,他希望展示一条从房子出发,经过一些字段,最后到达谷仓的最短路线,且不能重复走同一路径。题目转化为寻找两条不重复的最短路径。利用费用流算法可以解决此问题,通过建立源点、汇点,设置特殊边和普通边的费用和容量,运行费用流得到最短总距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Farm Tour

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 19376 Accepted: 7527

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 which contains his house and the Nth of which contains the big barn. A total M (1 <= M <= 10000) paths that connect the fields in various ways. Each path connects two different fields and has a nonzero length smaller than 35,000. 

To show off his farm in the best way, he walks a tour that starts at his house, potentially travels through some fields, and ends at the barn. Later, he returns (potentially through some fields) back to his house again. 

He wants his tour to be as short as possible, however he doesn't want to walk on any given path more than once. Calculate the shortest tour possible. FJ is sure that some tour exists for any given farm.

Input

* Line 1: Two space-separated integers: N and M. 

* Lines 2..M+1: Three space-separated integers that define a path: The starting field, the end field, and the path's length. 

Output

A single line containing the length of the shortest tour. 

Sample Input

4 5
1 2 1
2 3 1
3 4 1
1 3 2
2 4 2

Sample Output

6

题目大意:FJ的农场包括N块地,1是他的家,N是大谷仓,中间有m条路,他要从家到大谷仓再返回家,每条路只能走一次,而且要走最短距离

之前遇到一个题是问有多少条最短路,而且只能走一边,用的是最大流,所以这道题也想到了最大流,但是有了最短距离的限制,容易想到用费用流,其实问题等同于是求从1到n有2条不重复的路径的总的距离(当然要尽量短),所以我们设置源点汇点,源点与第一个点连一条费用为0,容量为2的边,最后一个点向汇点连一条费用为0,容量为2的边,至于在无向图中的边,就连一条费用为权值,容量为1的边,跑费用流就可以了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxm=2e4+7;
const int maxn=2e4+7;
const int inf=0x3f3f3f3f;
struct Node
{
    int to;
    int capa;
    int cost;
    int next;
}edge[maxm<<2];
int cnt;
int source,sink;
int head[maxn];
int dis[maxn];
bool vis[maxn];
int rec[maxn];
int pre[maxn];
void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
    return;
}
void add(int u,int v,int capa,int cost)
{
    edge[cnt].to=v;
    edge[cnt].capa=capa;
    edge[cnt].cost=cost;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].to=u;
    edge[cnt].capa=0;
    edge[cnt].cost=-cost;
    edge[cnt].next=head[v];
    head[v]=cnt++;
    return;
}
bool spfa()
{
    memset(dis,inf,sizeof(dis));
    memset(vis,false,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    memset(rec,-1,sizeof(rec));
    queue<int> que;
    dis[source]=0;
    vis[source]=true;
    que.push(source);
    while(!que.empty())
    {
        int node=que.front();
        que.pop();
        vis[node]=false;
        for(int i=head[node];~i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(edge[i].capa>0&&dis[v]>dis[node]+edge[i].cost)
            {
                dis[v]=dis[node]+edge[i].cost;
                rec[v]=i;
                pre[v]=node;
                if(!vis[v])
                {
                    vis[v]=true;
                    que.push(v);
                }
            }
        }
    }
    return dis[sink]!=inf;
}
int mcmf()
{
    int maxflow=0;
    int mincost=0;
    while(spfa())
    {
        int flow=inf;
        int node=sink;
        while(node!=source)
        {
            flow=min(flow,edge[rec[node]].capa);
            node=pre[node];
        }
        maxflow+=flow;
        node=sink;
        while(node!=source)
        {
            mincost+=flow*edge[rec[node]].cost;
            edge[rec[node]].capa-=flow;
            edge[rec[node]^1].capa+=flow;
            node=pre[node];
        }
    }
    return mincost;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=0;i<m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,1,w);
            add(v,u,1,w);
        }
        source=0;
        sink=n+1;
		add(source,1,2,0);
        add(n,sink,2,0);
        printf("%d\n",mcmf());
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值