题意一开始不是很好理解,然后考试的时候就把它跳过了。。
题意:有M年,N个城市,每年最多修建K个城市。然后会发生一系列的事件,包括拆一条边,加一条边,对x所在的连通块中的城市进行重修。每个城市最多重修一次,求最多有多少城市可以被重修,然后输出每一个发生重修事件的年份实际修了多少城市,要求字典序最小。N,M都在几百左右。
其实就是按着他的步骤模拟一下,如果遇到可修的年份,就向连通块里面全部连上边。但是要注意,同一个年份可以被用K次,所以如果用匈牙利匹配的话需要将一个年份拆成K个,然后倒序匹配。如果用网络流的话,就不需要拆点了,直接把流量上调就行了,但是网络流不好控制字典序,一个比较暴力的做法就是强行给边上设费用,让编号小的边费用更大。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define LL long long
#define clr(a) memset(a,0,sizeof a)
const int inf = 0x3f3f3f3f;
const int MAXN = 1005;
const int MAXM = 500000;
int N, M, K;
struct Ed {
int to, cap, cost;
Ed*nxt, *back;
};
struct FlowNet
{
Ed Edge[MAXM], *ecnt, *adj[MAXN];
FlowNet () { ecnt=Edge; }
int dis[MAXN];
bool vis[MAXN];
int vn, S, T, tot, flow;
inline void adde(int a, int b, int c, int d)
{
(++ecnt)->to = b;
ecnt->cap = c;
ecnt->cost = d;
ecnt->nxt = adj[a];
ecnt->back = ecnt+1;
adj[a] = ecnt;
(++ecnt)->to = a;
ecnt->cap = 0;
ecnt->cost = -d;
ecnt->nxt = adj[b];
ecnt->back = ecnt-1;
adj[b] = ecnt;
}
void init(int n, int s, int t)
{
tot = flow = 0;
vn = n; S = s; T = t;
clr(dis), clr(adj);
ecnt = Edge;
}
bool update()
{
int tmp = inf;
for (int i = 1; i<=vn; ++i)
if (vis[i]) for (Ed *p = adj[i]; p; p=p->nxt)
if (p->cap > 0 && !vis[p->to])
tmp = min(tmp, dis[p->to]-dis[i]+p->cost);
if (tmp == inf) return 0;
for (int i = 1; i<=vn; ++i)
if (vis[i]) dis[i] += tmp;
return 1;
}
int aug(int u, int augco)
{
if (u == T)
{
tot += dis[S] * augco;
flow += augco;
return augco;
}
vis[u] = 1;
int delta, augc = augco;
for (Ed*p = adj[u]; p && augc; p=p->nxt)
{
int&v = p->to;
if (!vis[v] && p->cap && dis[u]==dis[v]+p->cost)
{
delta = aug(v, min(p->cap, augc));
p->cap -= delta, p->back->cap += delta;
augc -= delta;
}
}
return augco - augc;
}
int mcmf()
{
do {
do memset(vis, 0, sizeof vis); while (aug(S, inf));
} while (update());
return tot;
}
void calc(int *ans, int yeah)
{
for (Ed*p = adj[S]; p; p=p->nxt)
if (p->to > 0 && p->to <= yeah)
ans[p->to] = p->back->cap;
}
void debug()
{
for (Ed*p = adj[T]; p; p=p->nxt)
if (p->cap) printf("city %d:%d\n", p->to-M, p->cap);
}
} G;
bool way[MAXN][MAXN];
int scc[MAXN], cnt, yeah;
bool vis[MAXN];
int ans[MAXN];
void dfs(int u)
{
vis[u] = 1, scc[++cnt] = u;
rep(v, 1, N) if (way[u][v] && !vis[v]) dfs(v);
}
int main()
{
int cas, op, x, y, duang;
scanf("%d", &cas);
while (cas --)
{
scanf("%d%d%d", &N, &M, &K);
G.init(M+N+2, M+N+1, M+N+2);
clr(way);
yeah = 0;
rep (id, 1, M)
{
scanf("%d", &op);
switch (op)
{
case 1:
G.adde(G.S, ++yeah, K, M-id);
scanf("%d", &x);
clr(vis), cnt = 0, dfs(x);
rep(i, 1, cnt) G.adde(yeah, M+scc[i], 1, 0);
break;
case 2:
scanf("%d%d", &x, &y);
way[x][y] = way[y][x] = 1;
break;
default:
scanf("%d", &duang);
while (duang--)
scanf("%d%d", &x, &y), way[x][y] = way[y][x] = 0;
}
}
rep(i, 1, N) G.adde(M+i, G.T, 1, 0);
G.mcmf();
printf("%d\n", G.flow);
G.calc(ans, yeah);
rep(i, 1, yeah)
printf("%d%c", ans[i], i==yeah?'\n':' ');
//G.debug();
}
return 0;
}