[BZOJ1877] [SDOI2009]晨跑

题目描述

Description

Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑、仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑。 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道,Elaxia只能从 一个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交。Elaxia每天从寝室出发 跑到学校,保证寝室编号为1,学校编号为N。 Elaxia的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以 在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路 口。Elaxia耐力不太好,他希望在一个周期内跑的路程尽量短,但是又希望训练周期包含的天 数尽量长。 除了练空手道,Elaxia其他时间都花在了学习和找MM上面,所有他想请你帮忙为他设计 一套满足他要求的晨跑计划。

Input

第一行:两个数N,M。表示十字路口数和街道数。 接下来M行,每行3个数a,b,c,表示路口a和路口b之间有条长度为c的街道(单向)。

Output

两个数,第一个数为最长周期的天数,第二个数为满足最长天数的条件下最短的路程长 度。

Sample Input

7 10
1 2 1
1 3 1
2 4 1
3 4 1
4 5 1
4 6 1
2 5 5
3 6 6
5 7 1
6 7 1

Sample Output

2 11

HINT

对于30%的数据,N ≤ 20,M ≤ 120。
对于100%的数据,N ≤ 200,M ≤ 20000。

题目分析

学了一发费用流
这题因为十字路口和街道都不能重复 那么我们将边的流量设为1 对十字路口拆点就好了
注意 费用流的反向边边权是-c 并且tot初始是1

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
int n,m;
int head[1000],to[100000],val[100000],net[100000],flo[100000];
int tot=1;
int path[10000];
void add(int x,int y,int v,int c)
{
    net[++tot]=head[x],head[x]=tot,to[tot]=y,flo[tot]=v,val[tot]=c;
    net[++tot]=head[y];head[y]=tot,to[tot]=x,flo[tot]=0,val[tot]=-c;
}
int dis[10000],vis[10000];
int spfa()
{
    memset(dis,0x3f,sizeof dis);
    memset(vis,0,sizeof vis);
    queue<int>q;
    vis[1]=1,q.push(1),dis[1]=0;
    while(q.size())
    {
        int nmp=q.front();
        q.pop();
        vis[nmp]=0;
        for(int i=head[nmp];i;i=net[i])
            if(flo[i]>0&&dis[to[i]]>dis[nmp]+val[i])
            {
                dis[to[i]]=dis[nmp]+val[i];
                path[to[i]]=i^1;
                if(!vis[to[i]]) q.push(to[i]),vis[to[i]]=1;
            }
    }
    return dis[n]<0x3f3f3f3f;
}
int sum;
int mincost()
{
    int ans=0;
    while(spfa())
    {
        sum++;
        int minflow=1<<30;
        for(int i=n;i!=1;i=to[path[i]]) minflow=min(minflow,flo[path[i]^1]);
        for(int i=n;i!=1;i=to[path[i]])
        {
            flo[path[i]]+=minflow;
            flo[path[i]^1]-=minflow;
            ans+=val[path[i]^1]*minflow;
        }
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);
        if(x!=1) x+=n;
        add(x,y,1,c);
    }
    for(int i=1;i<=n;i++) add(i,i+n,1,0);
    printf("%d %d",sum,mincost());
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注