分析:
首先假设答案为T。构图如下:
把原图的每个点u拆成T+1个,分别为u0,u1,......, 其中u0是初始状态的结点u,ui表示经过i天之后的结点u。对于原图中的相邻结点a和b,在新图中添加一条从ai到bi+1的边,容量为1,再添加一条bi到ai+1的边,容量也为1。对于原图中的每个结点u,添加
ui->ui+1,容量为无穷大,表示飞船可以原地不动。在此图中求最大流,判断流量是否至少为k即可。
逐步增大天数T,每次不要重新求最大流,直接加上一层结点,在上次求出的最大流基础上继续增广,直到流量达到k。
注意,同一时刻ai->bi+1和bi->ai+1不能同时有流量。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int INF = 1e9;
const int maxn = 5000+10;
const int maxm = 200+10;
struct Edge{
int from,to,cap,flow;
};
bool operator < (const Edge &a,const Edge &b){
return a.from<b.from || (a.from == b.from && a.to<b.to);
}
vector<Edge>edges;
vector<int>G[maxn];
bool vis[maxn]; //BFS使用
int d[maxn]; //起点到i的距离
int cur[maxn]; //当前弧指针
int n,m,s,t,k;
int u[maxm],v[maxm];
queue<int>que;
void clearNodes(int a, int b){
for (int i=a; i<=b; i++) G[i].clear();
}
void init(){
edges.clear();
clearNodes(0,n-1);
for (int i=0; i<m; i++) scanf("%d %d",&u[i],&v[i]);
}
int sz;
void AddEdge(int from, int to, int cap){
edges.push_back((Edge){from,to,cap,0});
edges.push_back((Edge){to,from,0,0});
sz = edges.size();
G[from].push_back(sz-2);
G[to].push_back(sz-1);
}
bool BFS(int s, int t){
memset(vis,0,sizeof(vis));
while (!que.empty()) que.pop();
que.push(s);
vis[s] = 1;
d[s] = 0;
int x;
while (!que.empty()){
x = que.front();
que.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;
que.push(e.to);
}
}
}
return vis[t];
}
inline int MIN(int x, int y){return x<y?x:y;}
int DFS(int x,int t, int a){
if (x==t || a==0) 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,t,MIN(a,e.cap-e.flow)))>0){
flow += f;
a -= f;
e.flow += f;
edges[G[x][i]^1].flow -= f;
if (a==0) break;
}
}
return flow;
}
int MAXflow(int s, int t, int limit){
int flow = 0;
while (BFS(s,t)){
memset(cur,0,sizeof(cur));
flow += DFS(s,t,limit-flow);
if (flow==limit) break;
}
return flow;
}
int day,flow;
void Print(){
printf("%d\n",day);
int idx = 0;
vector<int> location(k,s);
for (int d=1; d<=day; d++){
idx += n*2;
vector<int>moved(k,0);
vector<int>a,b;
for (int i=0; i<m; i++) {
int f1 = edges[idx].flow; idx+=2;
int f2 = edges[idx].flow; idx+=2;
if (f1==1 && f2==0) {a.push_back(u[i]); b.push_back(v[i]);}
if (f1==0 && f2==1) {a.push_back(v[i]); b.push_back(u[i]);}
}
printf("%d",a.size());
for (int i=0; i<a.size(); i++) {
//查找哪架飞船从a[i]移动到b[i]
for (int j=0; j<k; j++)
if (!moved[j] && location[j]==a[i]){
printf(" %d %d",j+1,b[i]);
moved[j] = 1;
location[j] = b[i];
break;
}
}
printf("\n");
}
}
int main(){
while (scanf("%d %d %d %d %d",&n,&m,&k,&s,&t)==5){
init();
day = 1, flow = 0;
for (;;){
clearNodes(day*n,day*n+n-1);
for (int i=0; i<n; i++) AddEdge((day-1)*n+i,day*n+i,INF);
for (int i=0; i<m; i++) {
AddEdge((day-1)*n + u[i]-1, day*n+v[i]-1,1);
AddEdge((day-1)*n + v[i]-1, day*n+u[i]-1,1);
}
flow += MAXflow(s-1, day*n + t-1, k-flow);
if (k==flow) break;
day++;
}
Print();
}
return 0;
}