Problem:
Problem E: School Excursion

春、それは修学旅行の時期である。
会津大学附属小学校（会津大小）でも、来年度の修学旅行の計画が建てられていた。
修学旅行は電車で移動することが伝統になっている。
会津若松市内では電車を利用する機会が少ないためだ。

しかし、学校に届いたある苦情により教員たちは頭を悩ませていた。
それは、「ある駅で大人数で乗り換えを行っていたので、その駅を利用する他の乗客に迷惑であった」という内容だった。
とくに、電車を降りたあとホームからの通路で大混雑してしまったという。

それは近年、会津大小の生徒数が急上昇しているからであった。
その原因は日本において競技プログラミングが大流行し、
小学校から競技プログラマーを養成するための訓練を行っている会津大小に生徒が集まったからである。

会津大小競技プログラミング部長であるあなたは、修学旅行を楽しみにしている。
修学旅行を成功させたいあなたは教員たちに提案をした。
「クラスごとに行動して、同じ駅に同時に到着しないようにしましょう！！　競技プログラミングの知識を応用すれば簡単です！！」

複数のクラスが同時に同じ駅に到着することがないように移動するとき（同じ駅に複数のクラスが滞在することは可能）、
出発する駅から目的地まで到達できる最大のクラス数を求め、そのときの最小の運賃を求めるプログラムをつくりなさい。
ただし、ある駅で同時に到着する電車と発車する電車が存在する場合、乗り継ぎが可能である。つまり、乗り継ぎに要する時間は無視して良い。

Input

入力は複数のデータセットから構成される。
データセットの数は20個以下である。
各データセットの形式は次に示す通りである。

n
m1
x1,1 y1,1 c1,1
x1,2 y1,2 c1,2
...
x1,m1 y1,m1 c1,m1
m2
x2,1 y2,1 c2,1
x2,2 y2,2 c2,2
...
x2,m2 y2,m2 c2,m2
...
mn-1
xn-1,1 yn-1,1 cn-1,1
xn-1,2 yn-1,2 cn-1,2
...
xn-1,m2 yn-1,m2 cn-1,m2
g

n( 2 ≤ n ≤ 100)は駅の数を表す。
駅の数は出発する駅と目的地の駅、乗り換えする駅を含む。
駅は出発する駅を1番目、最初に乗り換える駅を2番目の駅と数え、目的地をn番目の駅とする。
miはi番目の駅からi+1番目の駅への電車の数を表す。
mi(1 ≤ m ≤ 20)個の電車の情報が続く。
xi,j yi,j ci,j
はi番目の駅からi+1番目の駅に向かう電車の出発時刻(xi,j)到着時刻(yi,j)運賃(ci,j)を表す。
(0 ≤ xi,j, yi,j ≤ 200000 かつ xi,j ≤ yi,j)
(1 ≤ ci,j ≤ 1000)

その後g(1≤ g ≤ 10)が続く。
gは修学旅行に参加するクラス数を表す。
与えられる数（n,m,x,y,c,g)はすべて整数である。
入力の終了はひとつの0を含む１行で示される。

Output

一行に到着可能なクラス数とそのときの最小運賃をこの順に出力せよ。
もし、ただ一つのクラスも到着できない場合は0 0を出力せよ。

Sample Input

2
4
1 2 10
2 2 5
1 3 20
2 3 10
10
3
2
1 2 5
0 3 4
3
10 11 100
2 12 2
12 12 3
10
0

Sample Output

2 15
2 111

Solution in C++ (judge verdict: Accepted)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
using namespace std;

#define V 10000
#define INF 100000000

typedef pair<int,int> P;

struct edge {
  int to,cap,cost,rev;
  edge(int a,int b,int c,int d){to = a;cap = b,cost = c;rev = d;}
};

int n,m[110],g,a;
int x[110][30],y[110][30],c[110][30];
vector<int> ar[110];

vector<edge> G[V];
int h[V];
int dist[V];
int prevv[V], preve[V];

void add_edge(int from,int to,int cap,int cost){
  G[from].push_back(edge(to,cap,cost,G[to].size()));
  G[to].push_back(edge(from,0,-cost,G[from].size() - 1));
}

int min_cost_flow(int s,int t,int f){
  int res = 0;
  fill(h,h+V,0);
  while(f>0){
    priority_queue<P ,vector<P>, greater<P> > q;
    fill(dist,dist+V,INF);
    dist[s] = 0;
    q.push(P(0,s));
    while(!q.empty()){
      P p = q.top(); q.pop();
      int v = p.second;
      if(dist[v] < p.first)continue;
      for(int i=0;i<G[v].size();i++){
	edge &e = G[v][i];
	if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]){
	  dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
	  prevv[e.to] = v;
	  preve[e.to] = i;
	  q.push(P(dist[e.to],e.to));
	}
      }
    }
    if(dist[t] == INF)return -1;

    for(int v=0;v<V;v++)h[v] += dist[v];

    int d = f;
    for(int v=t;v!=s;v = prevv[v]){
      d = min(d,G[prevv[v]][preve[v]].cap);
    }

    f -= d;
    res += d*h[t];
    for(int v=t;v!=s;v=prevv[v]){
      edge &e = G[prevv[v]][preve[v]];
      e.cap -= d;
      G[v][e.rev].cap += d;
    }
  }
  return res;
}

int main(){
  while(scanf("%d",&n) != EOF, n){
    m[0] = 1; ar[0].clear(); ar[0].push_back(0);
    x[0][0] = 0; y[0][0] = 0; c[0][0] = 0;
    for(int i=1;i<n;i++){
      scanf("%d",&m[i]);
      ar[i].clear();
      for(int j=0;j<m[i];j++){
	scanf("%d %d %d",&x[i][j],&y[i][j],&c[i][j]);
	ar[i].push_back(y[i][j]);
      }
      sort(ar[i].begin(),ar[i].end());
      ar[i].erase(unique(ar[i].begin(),ar[i].end()),ar[i].end());
    }
    m[n] = 1; ar[n].clear(); ar[n].push_back(INF);
    x[n][0] = INF; y[n][0] = INF; c[n][0] = 0;
    scanf("%d",&g);
    for(int ans = g;ans>=0;ans--){
      for(int i=0;i<V;i++)G[i].clear();
      for(int i=0;i<n;i++){
        for(int j=0;j<ar[i].size();j++){
    	  for(int k=0;k<m[i+1];k++){
            if(ar[i][j]<=x[i+1][k]){
              for(int l=0;l<ar[i+1].size();l++){
	        if(y[i+1][k] == ar[i+1][l]){
	       	  a = l;
		  break;
	        }
	      }
	      add_edge(i*50 + j*2 + 1, (i+1)*50 + a*2, 1, c[i+1][k]);
	    }
  	  }
        }
        for(int j=0;j<ar[i+1].size();j++){
	  add_edge((i+1)*50 + j*2,(i+1)*50 + j*2 + 1, 1, 0);
        }
      }
    
      int res = min_cost_flow(1,n*50,ans);
      if(0<=res){
        cout << ans << " " << res << endl;
        break;
      }
    }
  }
}