题意
有一个人喜欢跑步,他每天跑的路线都不一样,每个点只能走1次,而且每条路有一个长度。给出几条路线,求出他从点1到点n最多能用这些路线跑多少天并且在这个前提下跑的路程最短。
思路
有最短路程和最长天数我就知道是最小费用最大流了。把每条边的流量设为1,如果有一条路是1直接到n的,我们只能让他走一次。然后把每个点拆成入点和出点,把它们连起来,这样子让每个点只会被走过1次。构完图后跑一遍网络流就好了。
代码
#include<cstdio>
#include<cstring>
#include<queue>
#define min(a,b) a<b?a:b
using namespace std;
int S,T,tot,n,m,a,b,c,ans,head[403],d[403],v[403],p[403],ans1,ans2;
struct node{
int x,y,flow,cost,next;
}e[40804];
void add(int x,int y,int flow,int cost)
{
e[++tot].x=x;e[tot].y=y;e[tot].flow=flow;
e[tot].cost=cost;e[tot].next=head[x];
head[x]=tot;
e[++tot].x=y;e[tot].y=x;e[tot].flow=0;
e[tot].cost=-cost;e[tot].next=head[y];
head[y]=tot;
}
bool spfa()
{
queue<int> q;
int x,y;
for (int i=1;i<=2*n+2;i++)
{
v[i]=0;
d[i]=2147483647;
}
d[S]=0;q.push(S);v[S]=1;
while (q.size())
{
x=q.front();q.pop();v[x]=0;
for (int i=head[x];i;i=e[i].next)
{
if (!e[i].flow) continue;
y=e[i].y;
if (d[y]>d[x]+e[i].cost)
{
d[y]=d[x]+e[i].cost;
p[y]=i;
if (!v[y])
{
v[y]=1;
q.push(y);
}
}
}
}
return d[T]<2147483647;
}
void addflow()
{
int i=T,mn=2147483647;
while (p[i])
{
mn=min(mn,e[p[i]].flow);
i=e[p[i]].x;
}
ans1+=mn;ans2+=d[T]*mn;
i=T;
while (p[i])
{
e[p[i]].flow-=mn;
e[p[i]^1].flow+=mn;
i=e[p[i]].x;
}
}
int main()
{
tot=1;
scanf("%d%d",&n,&m);
S=2*n+1;T=2*n+2;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);//*2-1表示入点,*2表示出点
if (a==1&&b!=n) add(S,b*2-1,1,c);
else if (a!=1&&b==n) add(a*2,T,1,c);
else if (a==1&&b==n) add(S,T,1,c);
else add(a*2,b*2-1,1,c);
}
for (int i=2;i<n;i++)
add(i*2-1,i*2,1,0);//入点连出点
while (spfa())
addflow();
printf("%d %d",ans1,ans2);
}