[BZOJ 1877][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

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



解法:将每个点拆成两个点a和a‘,入边连到a,出边连到a',a到a'连边,容量为1,费用0,另外每条路容量也设为为1 ,费用为路的长度,对s到t求最小费用流即可,最长周期为流量,最短路程就是最小费用。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<deque>
using namespace std;
 
int n,m;
  
struct par
{
  int a, b;
  par(int _a = 0, int _b = 0) : a(_a), b(_b) {}
};
 
//===========================NetworkCostFlowZkw========
 
const int NCFZmaxn = 1005;
const int NCFZmaxm = 80005;
const int NCFZinf_ = 0x7f;
const int NCFZinf  = 0x7f7f7f7f;
 
struct NCFZ_Line
{
  int fr, to, next, v, c, opt;
};
 
struct Network_Cost_Flow_Zkw
{
  NCFZ_Line li[NCFZmaxm];
  int be[NCFZmaxn], l, s, t, dist[NCFZmaxn], b[NCFZmaxn];
  deque<int> q;
 
  void makeline(int fr, int to, int v, int c)
  {
    ++l;
    li[l].next = be[fr];
    be[fr] = l;
    li[l].fr = fr;
    li[l].to = to;
    li[l].v = v;
    li[l].c = c;
    li[l].opt = l + 1;
 
    ++l;
    li[l].next = be[to];
    be[to] = l;
    li[l].fr = to;
    li[l].to = fr;
    li[l].v = 0;
    li[l].c = -c;
    li[l].opt = l - 1;
  }
 
  void create()
  {
  }
 
  void clear()
  {
    l = s = t = 0;
    memset(be, 0, sizeof(be));
    memset(b, 0, sizeof(b));
  }
 
  bool spfa()
  {
    memset(dist, NCFZinf_, sizeof(dist));
    memset(b, 0, sizeof(b));
    dist[t] = 0;
    b[t] = 1;
    q.push_back(t);
    while (!q.empty())
    {
      int now = q.front();
      q.pop_front();
      for (int i = be[now]; i; i = li[i].next)
      {
        int to = li[i].to;
        if (!li[li[i].opt].v || dist[to] <= dist[now] - li[i].c) continue;
        dist[to] = dist[now] - li[i].c;
        if (!b[to])
        {
          b[to] = 1;
          if (!q.empty() && dist[to] < dist[q.front()]) q.push_front(to);
          else q.push_back(to);
        }
      }
      b[now] = 0;
    }
    return dist[s] != NCFZinf;
  }
 
  int sap(int now, int maxf)
  {
    if (now == t) return maxf;
    int tot = 0;
    b[now] = 1;
    for (int i = be[now]; i; i = li[i].next)
    {
      int to = li[i].to;
      if (!b[to] && li[i].v && dist[to] == dist[now] - li[i].c)
      {
        int k = sap(to, min(maxf - tot, li[i].v));
        li[i].v -= k;
        li[li[i].opt].v += k;
        tot += k;
      }
    }
    return tot;
  }
 
  par query(int S, int T)
  {
    par ans;
    ans.a = ans.b = 0;
    s = S, t = T;
    while (spfa())
      while (int k = sap(s, NCFZinf))
      {
        memset(b, 0, sizeof(b));
        ans.a += k;
        ans.b += k * dist[s];
      }
    return ans;
  }
};
 
//===========================NetworkCostFlowZkw========
 
Network_Cost_Flow_Zkw map;
     
int main(){
    scanf("%d%d",&n,&m);
 
    map.clear();
    for(int i=2;i<=n-1;i++){
        map.makeline(2*i-1,2*i,1,0);
    }
    map.makeline(1,2,0xffffff,0);
    map.makeline(2*n-1,2*n,0xffffff,0);
    int u,v,d;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&u,&v,&d); 
        map.makeline(2*u,2*v-1,0x1,d);
    }
    par ans;
    ans=map.query(2,2*n-1);
    printf("%d %d\n",ans.a,ans.b);
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值