poj 2135

思路:由于要求两条不重合边的单源最短路,所以可以考虑用最小费用最大流来做。

设虚拟起点vstart到1的容量为2,cost为0,虚拟终点vend到n的容量为2,cost为1,其他的边的容量为1,cost为输入的值。

那么其实就是求这个构造的图的最小费用最大流了。

我看到很多都是用next数组神马的,啊啊,对于我这样的懒家伙,于是想用vector。硬是把它给过了。

提示:边是双向的,所以要加入两条边,再加上自身的反向边(其实就是用来执行“反悔“操作的),总共有4条边要加入。但是,对于虚拟的起点和终点的话,大家自己想吧。

资料推荐:http://comzyh.tk/blog/archives/568/

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cstring>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int MAXN=1e9;

struct node
{
    int cost;
    int from;
    int to;
    int cap;
    int flow;
}edge[1010*1010];

vector<int>w[1010];
int mark[1010];
int get[1010];
int path[1010];
int pre[1010];
int step;

bool MCMF(int vstart,int vend,int &flow,int &cost)
{
    for(int ii=vstart;ii<=vend;ii++){mark[ii]=0;path[ii]=MAXN;get[ii]=MAXN;}
    queue<int>q;
    q.push(vstart);
    path[vstart]=0;
    pre[vstart]=vstart;
    while(!q.empty())
    {
        int tt=q.front();
        q.pop();
        mark[tt]=0;
        int len=w[tt].size();
        for(int ii=0;ii<len;ii++)
        {
            int son=w[tt][ii];
            node e=edge[son];
            if(e.cap>e.flow&&path[e.to]>path[tt]+e.cost)
            {
                path[e.to]=path[tt]+e.cost;
                get[e.to]=min(get[tt],e.cap-e.flow);
                pre[e.to]=son;
                if(!mark[e.to])
                {
                    q.push(e.to);
                    mark[e.to]=1;
                }
            }
        }
    }
    if(path[vend]==MAXN)return false;
    flow+=get[vend];
    cost+=path[vend]*get[vend];
    int uu=vend;
    while(uu!=vstart)
    {
        edge[pre[uu]].flow+=get[vend];
        edge[pre[uu]^1].flow-=get[vend];
        uu=edge[pre[uu]].from;
    }
    return true;
}
void add2(int ss,int ee,int cost,int many)
{
    w[ee].push_back(step);
    edge[step].from=ee;
    edge[step].to=ss;
    edge[step].cost=cost;
    edge[step].flow=0;
    edge[step++].cap=many;

    w[ss].push_back(step);
    edge[step].from=ss;
    edge[step].to=ee;
    edge[step].cost=-cost;
    edge[step].flow=0;
    edge[step++].cap=0;
}

void add1(int ss,int ee,int cost,int many,int kk)
{
    w[ss].push_back(step);
    edge[step].from=ss;
    edge[step].to=ee;
    edge[step].cost=cost;
    edge[step].flow=0;
    edge[step++].cap=many;

    w[ee].push_back(step);
    edge[step].from=ee;
    edge[step].to=ss;
    edge[step].cost=-cost;
    edge[step].flow=0;
    edge[step++].cap=0;
    if(kk==0)add2(ss,ee,cost,many);
    return ;
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(edge,0,sizeof(edge));
        step=0;
        for(int ii=0;ii<=n+1;ii++)w[ii].clear();
        while(m--)
        {
            int x,y,t;
            scanf("%d%d%d",&x,&y,&t);
            add1(x,y,t,1,0);
        }
        add1(0,1,0,2,1);
        add1(n,n+1,0,2,1);
        int flow=0;
        int cost=0;
        while(MCMF(0,n+1,flow,cost));
        printf("%d\n",cost);
    }
    return 0;
}


 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值