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

Data Constraint

Hint

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

题解

观察题目,发现是裸的最小费用最大流,但是注意到每个点只能经过一次,那么就把其拆成两个点,流量为1就可以解决这一类问题了

贴代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#define fo(i,a,b) for (i=a;i<=b;i++)
const int maxn=410;

int la[maxn],h[10*maxn*maxn],val[maxn];
int va[maxn][maxn],map[maxn][maxn];
int i,j,k,l,m,n,x,y,z,ans;
bool bz;
bool b[maxn],bc[maxn];
void spfa(){
    int i,j,k;
    i=1;
    j=0;
    la[1]=0;
    h[1]=1;
    memset(val,127,sizeof(val));
    val[1]=0;
    memset(b,false,sizeof(b));
    while (i>j){
        j++;
        if (b[h[j]]) continue;
        b[h[j]]=true;
        fo (k,1,2*n)
        if (map[h[j]][k]>0 && val[k]>val[h[j]]+va[h[j]][k]){
            val[k]=val[h[j]]+va[h[j]][k];
            la[k]=h[j];
            b[k]=false;
            i++;
            h[i]=k;
        }
    }
}
int ad(){
    int x,tt;
    x=2*n; tt=0;
    while (x){
        tt+=va[la[x]][x];
        x=la[x];
        map[la[x]][x]--;
        map[x][la[x]]++;
    }
    if (tt<=0){
        bz=false;
        return 0;
    }
    return tt;
}
void get_ans(){
    bz=true;
    while (bz){
        la[n+n]=0;
        spfa();
        ans+=ad();
    }
}
int main(){
    //freopen("1090.in","r",stdin);
    scanf("%d%d",&n,&m);
    fo (i,1,m){
        scanf("%d%d%d",&x,&y,&z);
        map[x+n][y]=1;
        va[x+n][y]=z; va[y][x+n]=-z;
        if (y==n) bc[x]=true;
    }
    fo (i,2,n-1) map[i][i+n]=1;
    map[1][n+1]=map[n][2*n]=12345678;
    get_ans();
    z=0;
    fo(i,1,n-1) if (bc[i]==true && map[i+n][n]==0) z++;
    printf("%d %d\n",z,ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值