NKOI 1589 农场观光

P1589农场观光
时间限制 : 10000 MS   空间限制 : 65536 KB
问题描述

每当FJ的朋友来拜访他时,FJ总喜欢带着他们到自己的农场去转转。他的农场由N(1<=N<=1000)个牧场构成,编号1到N。FJ的房子在1号牧场,在N号牧场有一个巨大的谷仓。有M(1<=M<=10000)条道路将这N个牧场连接了起来。每条路连接两个牧场,长度不超过35000。

为了炫耀他的巨大谷仓,FJ总是从他的房子出发,带着朋友们穿过一些牧场,最后来到谷仓。然后再从谷仓出发穿过一些牧场回到他的房子。

FJ想让这条观光的线路尽可能的短,但一条路他只愿意走一次,不喜欢重复走。请你计算出最短的观光线路。FJ向你保证这样的观光线路一定存在。

输入格式

第一行,两个空格间隔的整数N和M。
接下来M行,每行三个空格间隔的整数X,Y,Z,表示牧场X和Y之间有一条长度为Z的道路。

输出格式

一个整数,表示最短线路的长度。

样例输入

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

样例输出

6



经验告诉我们这是一道网络流类型的题,由于每条边有边权因此是费用最小问题
比较麻烦的是这题的边为无向边,也就是说对于每一个输入的边我们一共要加入4条边:正反两边和其对应的"反边"
然后在1的左边放源点,n右边放汇点,就是裸的费用最小问题了
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=1005,inf=1e9,maxm=50005;
int n,m,mincost,maxflow,op,ed;
int dis[maxn],path[maxn],last[maxm];
bool flag[maxn];    
struct wr{ 
    int a,b,c,w,NEXT; //这里将流量当做一条边的参数
    wr(int a,int b,int w,int c,int NEXT):a(a),b(b),w(w),c(c),NEXT(NEXT){} 
}; 
vector<wr>s; 
void insert(int a,int b,int w,int c){
    s.push_back(wr(a,b,w,c,last[a])); 
    last[a]=s.size()-1; 
    s.push_back(wr(b,a,-w,0,last[b])); 
    last[b]=s.size()-1; 
} 
struct wk{       
    int  n;            
    void init(int n){ 
        this->n =n; 
        memset(last,-1,sizeof(last)); 
    }                          
    bool find(int st,int nd){       
        int i;
		queue<int>q;       
        for(i=1;i<=n;i++)dis[i]=inf,path[i]=-1; 
        dis[st]=0,path[st]=0,flag[st]=1;   
		q.push(st);       
        while(!q.empty()){       
            int x=q.front();       
            q.pop();flag[x]=0;  
             for(i=last[x];i!=-1;i=s[i].NEXT){   
                 wr& e=s[i];         
                if(e.c>0&&dis[x]+e.w<dis[e.b]){       
                    dis[e.b]=dis[x]+e.w; 
                    path[e.b]=i;       
                    if(!flag[e.b]){       
                        q.push(e.b) ;       
                        flag[e.b]=1;       
                    }       
                }        
            }       
        }   
        return dis[nd]<inf;         
    }       
}spfa;   
void addflow(){ 
    int flow=inf,i; 
    for(i=ed;i!=op&&s[path[i]].a!=0;i=s[path[i]].a) 
        flow=min(flow,s[path[i]].c); 
    maxflow+=flow; 
    mincost+=dis[ed]; 
    for(i=ed;i!=op;i=s[path[i]].a){ 
        int x=path[i]; 
        s[x].c-=flow; 
        s[x^1].c+=flow; 
    } 
}   
int main(){ 
    int i,x,y,z; 
    scanf("%d%d",&n,&m); 
    spfa.init(ed=n+2);
    for(i=1;i<=m;i++){ 
        scanf("%d%d%d",&x,&y,&z); 
        insert(x,y,z,1);  
        insert(y,x,z,1);
    } 
    insert(op,1,0,2); 
    insert(n,ed,0,2); 
    while(spfa.find(op,ed))addflow(); 
    cout<<mincost;
}   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值