洛谷_2153 晨跑

题意

有一个人喜欢跑步,他每天跑的路线都不一样,每个点只能走1次,而且每条路有一个长度。给出几条路线,求出他从点1到点n最多能用这些路线跑多少天并且在这个前提下跑的路程最短。

思路

有最短路程和最长天数我就知道是最小费用最大流了。把每条边的流量设为1,如果有一条路是1直接到n的,我们只能让他走一次。然后把每个点拆成入点和出点,把它们连起来,这样子让每个点只会被走过1次。构完图后跑一遍网络流就好了。

代码

#include<cstdio>
#include<cstring>
#include<queue>
#define min(a,b) a<b?a:b
using namespace std;
int S,T,tot,n,m,a,b,c,ans,head[403],d[403],v[403],p[403],ans1,ans2;
struct node{
    int x,y,flow,cost,next;
}e[40804];
void add(int x,int y,int flow,int cost)
{
    e[++tot].x=x;e[tot].y=y;e[tot].flow=flow;
    e[tot].cost=cost;e[tot].next=head[x];
    head[x]=tot;
    e[++tot].x=y;e[tot].y=x;e[tot].flow=0;
    e[tot].cost=-cost;e[tot].next=head[y];
    head[y]=tot;
}
bool spfa()
{
    queue<int> q;
    int x,y;
    for (int i=1;i<=2*n+2;i++)
    {
        v[i]=0;
        d[i]=2147483647;
    }
    d[S]=0;q.push(S);v[S]=1;
    while (q.size())
    {
        x=q.front();q.pop();v[x]=0;
        for (int i=head[x];i;i=e[i].next)
        {
            if (!e[i].flow) continue;
            y=e[i].y;
            if (d[y]>d[x]+e[i].cost)
            {
                d[y]=d[x]+e[i].cost;
                p[y]=i;
                if (!v[y])
                {
                    v[y]=1;
                    q.push(y);
                }
            }
        }
    }
    return d[T]<2147483647;
}
void addflow()
{
    int i=T,mn=2147483647;
    while (p[i])
    {
        mn=min(mn,e[p[i]].flow);
        i=e[p[i]].x;
    }
    ans1+=mn;ans2+=d[T]*mn;
    i=T;
    while (p[i])
    {
        e[p[i]].flow-=mn;
        e[p[i]^1].flow+=mn;
        i=e[p[i]].x;
    }
}
int main()
{
    tot=1;
    scanf("%d%d",&n,&m);
    S=2*n+1;T=2*n+2;
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);//*2-1表示入点,*2表示出点
        if (a==1&&b!=n) add(S,b*2-1,1,c);
        else if (a!=1&&b==n) add(a*2,T,1,c);
        else if (a==1&&b==n) add(S,T,1,c);
        else add(a*2,b*2-1,1,c);
    }
    for (int i=2;i<n;i++)
        add(i*2-1,i*2,1,0);//入点连出点
    while (spfa()) 
        addflow();
    printf("%d %d",ans1,ans2);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值