题目描述不多说 思路把一个点拆成T个 不断枚举T并往图上连边加点 知道最大流等于k 最后打印方案 因为原弧和其反向弧总是在一起 所以可以直接枚举检验时候有流量
处理 a->b b->a的方法 显然这两条边是连续加入的 可快速找到对应的边 统计流量 如果同时有流量则不移动
特别注意!!! s进行最大流算法是要在刚好满足的时刻退出 不然会导致不存在的流量出现
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define MAXN 6000
#define MAXM 3000000
#define MAXK 500
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int, int> pii;
pii A[200+10];
int Move[MAXK+10], pos[MAXK+10];
int n, m, S, T, k;
template <int maxn, int maxm>
struct Isap
{
int ecnt;
int d[maxn+10], pre[maxn+10], cur[maxn+10], gap[maxn+10];
int adj[maxn+10];
struct node {
int v, next, c, f;
}Edge[maxm*2+10];
void init() { memset(adj, -1, sizeof(adj)); ecnt = 0; }
void addedge(int u, int v, int c)
{
Edge[ecnt].v = v;
Edge[ecnt].c = c;
Edge[ecnt].f = 0;
Edge[ecnt].next = adj[u];
adj[u] = ecnt++;
}
void add(int u, int v, int c)
{
addedge(u, v, c);
addedge(v, u, 0);
}
void init_dis(int t) // 据说单次意义不大的优化 多次小规模才会出现差距 仅仅是据说
{
queue <int> q;
memset(d, -1, sizeof(d));
memset(gap, 0, sizeof(gap));
d[t] = 0;
q.push(t);
while(!q.empty())
{
int u = q.front(); q.pop();
gap[d[u]]++;
for(int i = adj[u]; ~i; i = Edge[i].next)
{
int v = Edge[i].v;
if(d[v] == -1) { d[v] = d[u] + 1; q.push(v); }
}
}
}
int ISAP(int s, int t, int num, int limit)
{
init_dis(t);
int ans = 0, u = s;
int Flow = INF;
memcpy(cur, adj, sizeof(adj));
while(d[s] < num)
{
int &i = cur[u];
for(; ~i; i = Edge[i].next)
{
int v = Edge[i].v;
if(Edge[i].c > Edge[i].f && d[u] == d[v] + 1)
{
u = v;
pre[v] = i;
Flow = min(Flow, Edge[i].c - Edge[i].f);
if(u == t)
{
while(u != s) {
int j = pre[u];
Edge[j].f += Flow;
Edge[j^1].f -= Flow;
u = Edge[j^1].v;
}
ans += Flow;
Flow = INF;
}
if(ans == limit) return ans;
break;
}
}
if(i == -1)
{
if(--gap[d[u]] == 0) break;
int dmin = num - 1;
cur[u] = adj[u];
for(int j = adj[u]; ~j; j = Edge[j].next) if(Edge[j].c > Edge[j].f) dmin = min(dmin, d[Edge[j].v]);
d[u] = dmin+1;
gap[d[u]]++;
if(u != s) u = Edge[pre[u]^1].v;
}
}
return ans;
}
};
Isap <MAXN+10, MAXM+10> sap;
vector <pii> step;
void print_ans(int Day)
{
int id = 0;
for(int i = 0; i < k; i++) pos[i] = S;
for(int i = 1; i <= Day; i++)
{
id += 2 * n;
int j = 1;
step.clear();
for(int j = 0; j < m; j++)
{
int f1 = sap.Edge[id].f; id += 2;
int f2 = sap.Edge[id].f; id += 2;
if(f1 && !f2) step.push_back(make_pair(A[j].first % n, A[j].second % n));
else if(!f1 && f2) step.push_back(make_pair(A[j].second % n, A[j].first % n));
}
printf("%d", step.size());
memset(Move, 0, sizeof(Move));
for(int j = 0; j < step.size(); j++)
{
int u = step[j].first, v = step[j].second;
for(int p = 0; p < k; p++)
if(!Move[p] && pos[p] == u)
{
Move[p] = 1;
printf(" %d %d", p+1, v+1);
pos[p] = v;
break;
}
}
printf("\n");
}
}
int main()
{
while(scanf("%d%d%d%d%d", &n, &m, &k, &S, &T) == 5)
{
S--; T--;
sap.init();
int Day = 1, Flow = 0;
for(int i = 0; i < m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
u--; v--;
A[i] = make_pair(u, v);
}
for(;;)
{
int Last = (Day-1) * n, Now = Day * n;
for(int i = 0; i < n; i++)
sap.add(Last+i, Now+i, INF);
for(int i = 0; i < m; i++)
{
int u = A[i].first, v = A[i].second;
sap.add(Last+u, Now+v, 1);
sap.add(Last+v, Now+u, 1);
}
Flow += sap.ISAP(S, T + Now, (Day + 1) * n, k - Flow);
if(Flow >= k) break;
Day++;
}
printf("%d\n", Day);
print_ans(Day);
}
}