题目描述:
求跑完N个点的最小时间
题目分析:
神似最短路径覆盖
看到每个点经过一次,那就是cap的限制
花费即费用流
考虑如何建模.
先拆点
S-i的出点容量为1,花费为爆发费用
i的出点-T容量为1,花费为0
S向i的入点连容量为1,花费为0的边
u->v的出点连容量为1,花费为高速航行的费用
考虑由于求最大流,所以所有点的出点向汇点的连边都会流满。每个点的出点的到达方式即为此点的到达方式:
1.由源点流来:指在某一时刻瞬移到该星球。
2.由入点流来:指由其他星球沿航路到该星球。
流到该点出点的某入点对应的星球,在之前的某一时刻一定由某种合法方式达到过,追溯到头一定是某个瞬移到的点(因为图中没有环),“追溯”的过程就是这一条路径。注意为什么源点会向所有入点连费用为0的边,这条边的容量其实对应着这个点的出点到达后而产生的贡献。每个点的入点只连向它能到的出点,又由于图为DAG,所以一定存在必须瞬移(走源点到出点的边)的点,正确性也就显然了。换句话说,每个从源点直接流向出点的点是一条路径的起始点,它的入点因为出点的到达而有意义,之后就是整条路径的递推
题目链接:
Ac 代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define inf 0x7ffffff
const int maxm=20100;
int head[maxm],to[maxm<<1],net[maxm<<1],cost[maxm<<1],cap[maxm<<1];
int cnt=1;
int n,m;
inline void add(int u,int v,int c1,int c2){cnt++;to[cnt]=v,cap[cnt]=c1,cost[cnt]=c2,net[cnt]=head[u],head[u]=cnt;}
inline void addedge(int u,int v,int c1,int c2){add(u,v,c1,c2),add(v,u,0,-c2);}
namespace MCMF{
int dis[maxm],flow[maxm],id[maxm],pre[maxm];
int maxflow,mincost;
bool vis[maxm];
std::queue <int> dl;
inline bool SPFA(int s,int t)
{
memset(dis,127/3,sizeof(dis));
memset(pre,-1,sizeof(pre));
vis[s]=1,dl.push(s),pre[s]=0,dis[s]=0,flow[s]=inf;
while(!dl.empty())
{
int now=dl.front();
dl.pop();
vis[now]=0;
for(int i=head[now];i;i=net[i])
if(cap[i]&&dis[to[i]]>dis[now]+cost[i])
{
dis[to[i]]=dis[now]+cost[i];
pre[to[i]]=now;
id[to[i]]=i;
flow[to[i]]=std::min(cap[i],flow[now]);
if(!vis[to[i]]) dl.push(to[i]),vis[to[i]]=1;
}
}
return pre[t]!=-1;
}
inline void change_cap(int s,int t,int x)
{
int now=t;
while(now!=s)
{
cap[id[now]]-=x;
cap[id[now]^1]+=x;
now=pre[now];
}
}
inline int mcmf(int s,int t)
{
maxflow=mincost=0;
while(SPFA(s,t))
{
maxflow+=flow[t];
mincost+=flow[t]*dis[t];
change_cap(s,t,flow[t]);
}
return mincost;
}
}
int main()
{
scanf("%d%d",&n,&m);
int s=0,t=2*n+10;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
addedge(s,i,1,0);
addedge(s,i+n,1,x);
addedge(i+n,t,1,0);
}
for(int i=1;i<=m;i++)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
addedge(std::min(u,v),std::max(u,v)+n,1,c);
}
printf("%d\n",MCMF::mcmf(s,t));
return 0;
}
本文详细解析了一道经典的最小费用流问题,通过构建一个特殊的网络流模型,利用SPFA算法求解最小费用最大流,实现了求解跑完N个点的最小时间。代码示例清晰展示了如何设置网络流模型中的节点、边及其费用。
393

被折叠的 条评论
为什么被折叠?



