题意:现在有k个机子要从 s 运到 t ,点之间的路线有m条,双向边,每条边在同一天只能运一台机子(同一天从 u 到 v 或者 从 v 到 u,不能同时),每台机子需要一个飞船来运。输出把他们全都运送过去的最少天数,然后输出方案。
分析:先拆点,假设需要 T 天,那么一个点就拆成 a0,、a1、a2、a3、...、aT,就是按照时间来拆点。然后连边,由于飞船在某一天能够停在原地,对于每个点那么就 ai->a(i+1),cap 为INF,然后就是 m 条边,假设是边 u-v,那么就是 ui -> v(i+1),vi -> u(i+1),cap 为 1。然后的话,应该首先想到二分答案,然后求最大流,但是书里提供了一种更好的方法,就是一天一天的加上去,边也一层一层的加上去,在之前的基础上求最大流,到 k 了停止。但是这样输出方案时还是有问题,就是我们把一条边拆成了两条,如果这两条边同时有 flow 就不对了,所以输出的时候还要判断一下,不能同时有flow ,如果同时有,那就两者抵消,有一个边的情况下输出。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5010;
const int inf=1e9;
struct Edge
{
int from,to,cap,flow;
};
Edge a[220];
struct Dinic
{
int n,m,s,t;
vector<Edge>edges;
vector<int>G[maxn];
bool vis[maxn];
int cur[maxn],d[maxn];
void Addedge(int from,int to,int cap)
{
edges.push_back((Edge){from,to,cap,0});
edges.push_back((Edge){to,from,0,0});
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
void init(int n)
{
this->n=n;
edges.clear();
for(int i=0;i<maxn;i++)
G[i].clear();
}
bool bfs()
{
memset(vis,0,sizeof(vis));
queue<int>Q;
Q.push(s);
d[s]=0;
vis[s]=1;
while(!Q.empty())
{
int x=Q.front();Q.pop();
for(int i=0;i<G[x].size();i++)
{
Edge& e=edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to]=1;
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x,int a)
{
if(a==0||x==t)return a;
int flow=0,f;
for(int& i=cur[x];i<G[x].size();i++)
{
Edge& e=edges[G[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0)
{
e.flow+=f;
edges[G[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)
break;
}
}
return flow;
}
int maxflow(int s,int t,int limit)
{
this->s=s,this->t=t;
int flow=0;
while(bfs())
{
memset(cur,0,sizeof(cur));
flow+=dfs(s,limit);
if(flow>=limit)
return limit;
}
return flow;
}
}solver;
int main()
{
int n,m,s,k,t;
while(~scanf("%d%d%d%d%d",&n,&m,&k,&s,&t))
{
solver.init(n);
for(int i=1;i<=m;i++)
scanf("%d%d",&a[i].from,&a[i].to);
int day=1,flow=0;
while(1)
{
for(int i=1;i<=n;i++)
solver.Addedge((day-1)*n+i,day*n+i,inf);
for(int i=1;i<=m;i++)
{
int u=a[i].from,v=a[i].to;
solver.Addedge((day-1)*n+u,day*n+v,1);
solver.Addedge((day-1)*n+v,day*n+u,1);
}
flow+=solver.maxflow(s,day*n+t,k-flow);
if(flow>=k)
break;
day++;
}
printf("%d\n",day);
vector<int>location(k+1,s);
int idx=0;
while(day--)
{
idx+=n*2;
vector<int>u,v,moved(k+1,0);
for(int i=1;i<=m;i++)
{
int f1=solver.edges[idx].flow;idx+=2;
int f2=solver.edges[idx].flow;idx+=2;
if(f1&&!f2)
{
u.push_back(a[i].from);
v.push_back(a[i].to);
}
if(!f1&&f2)
{
u.push_back(a[i].to);
v.push_back(a[i].from);
}
}
printf("%d",u.size());
for(int i=0;i<u.size();i++)
{
for(int j=1;j<=k;j++)
if(!moved[j]&&location[j]==u[i])
{
printf(" %d %d",j,v[i]);
location[j]=v[i];
moved[j]=1;
break;
}
}
printf("\n");
}
}
return 0;
}