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。
对于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;
}