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

存在1→n的边存在。这种情况下,这条边只能走一次。

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

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

输入输出样例
输入 #1 复制

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
输出 #1 复制
2 11
说明/提示
对于30%的数据,N ≤ 20,M ≤ 120。

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


很明显的费用流,现在主要目的就是建图。题目要求一个点只能经过一次,所以我们拆点限流即可,建图完毕。


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=410,M=8e4+10;
const int inf=0x3f3f3f3f;
int n,m,h[N],s,t,v[N],e[N],d[N];
int head[N],nex[M],to[M],w[M],flow[M],tot=1;
inline void ade(int a,int b,int c,int d){
	w[++tot]=d; flow[tot]=c; to[tot]=b; nex[tot]=head[a]; head[a]=tot;
}
inline void add(int a,int b,int c,int d){
	ade(a,b,c,d);	ade(b,a,0,-d);
}
int spfa(){
	memset(d,inf,sizeof d);	d[s]=0;	queue<int> q;	q.push(s);
	int vis[N]={0};	vis[s]=1;
	while(q.size()){
		int u=q.front();	q.pop();	vis[u]=0;
		for(int i=head[u];i;i=nex[i]){
			if(flow[i]&&d[to[i]]>d[u]+w[i]){
				d[to[i]]=d[u]+w[i];
				v[to[i]]=u; e[to[i]]=i;
				if(!vis[to[i]])	q.push(to[i]),vis[to[i]]=1;
			}
		}
	}
	return d[t]!=inf;
}
void EK(){
	int res=0,maxflow=0;
	while(spfa()){
		int mi=0x3f3f3f3f;
		for(int i=t;i!=s;i=v[i])	mi=min(mi,flow[e[i]]);
		for(int i=t;i!=s;i=v[i])	flow[e[i]]-=mi,flow[e[i]^1]+=mi;
		res+=d[t];	maxflow+=mi;
	}
	cout<<maxflow<<' '<<res<<endl;
}
signed main(){
	cin>>n>>m;	s=1;	t=n<<1;
	for(int i=1;i<=n;i++){
		if(i==1||i==n)	add(i*2-1,i<<1,inf,0);
		else	add(i*2-1,i<<1,1,0);
	}
	while(m--){
		int a,b,c;	cin>>a>>b>>c;	add(a*2,b*2-1,1,c);
	}
	EK();
	return 0;
}