题目大意
给定了
N
个小球,
M≤100,N≤300 。
题解
假设最后存在一种方案使得所有盒子都是好的,那么显然就是一个简单的二分图匹配。那么我们可以往匹配这方面想。
我们将一个盒子
j
拆为3个点,
于是我们就可以得到一个算法。将每个盒子拆为3个点,并连为一个三元环,对于一个球
但可以发现的是,我们构出来的图不是一个二分图,所以要用带花树来做匹配。(这也是我们不能用网络流解决这道题的原因)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 2005,MAXM = MAXN * MAXN;
int To[MAXM],Next[MAXM],Final[MAXN],Match[MAXN],tot;
int Vis[MAXN],Type[MAXN],Bel[MAXN],Q[MAXN],Fa[MAXN],N,M,tag,Ans,En;
void Link(int u,int v)
{
To[++ tot] = v,Next[tot] = Final[u],Final[u] = tot;
To[++ tot] = u,Next[tot] = Final[v],Final[v] = tot;
}
int Get(int a)
{
return Bel[a] == a ? a : Bel[a] = Get(Bel[a]);
}
void read(int &x)
{
char c;
while (c = getchar(),c < '0' || c > '9');
x = c - 48;
while (c = getchar(),c >= '0' && c <= '9') x = x * 10 + c - 48;
}
int GetLCA(int u,int v)
{
++ tag;
while (u || v)
{
if (u)
{
u = Get(u);
if (Vis[u] == tag) return u;
Vis[u] = tag;
u = Fa[Match[u]];
}
swap(u,v);
}
}
void Union(int u,int r)
{
while (u != r)
{
int v = Match[u],b = Fa[v];
if (Get(b) != r) Fa[b] = v;
if (Type[v] == 2) Type[Q[++ En] = v] = 1;
if (Bel[u] == u) Bel[u] = r;
if (Bel[v] == v) Bel[v] = r;
u = b;
}
}
bool Aug(int s)
{
for(int i = 1;i <= N;i ++)
Type[i] = 0,Bel[i] = i,Fa[i] = 0;
En = 1;
Q[1] = s;
Type[s] = 1;
for(int i = 1;i <= En;i ++)
{
int u = Q[i];
for(int j = Final[u];j;j = Next[j])
{
int v = To[j];
if (Match[u] == v || Type[v] == 2 || Get(u) == Get(v)) continue;
if (Type[v] == 1)
{
int r = GetLCA(u,v);
if (Get(u) != r) Fa[u] = v;
if (Get(v) != r) Fa[v] = u;
Union(u,r),Union(v,r);
} else
{
if (!Match[v])
{
Fa[v] = u;
for(;v;)
{
int mv = Match[Fa[v]];
Match[v] = Fa[v],Match[Fa[v]] = v;
v = mv;
}
return 1;
} else
{
Fa[v] = u;
Type[v] = 2;
Type[Q[++ En] = Match[v]] = 1;
}
}
}
}
return 0;
}
void Work()
{
tot = 0;
memset(Final,0,sizeof Final),memset(Match,0,sizeof Match);
int e;
read(N),read(M),read(e);
for(int i = 0;i < M;i ++) Link(i * 3 + 1,i * 3 + 2),Link(i * 3 + 2,i * 3 + 3),Link(i * 3 + 3,i * 3 + 1);
for(int i = 1;i <= e;i ++)
{
int u,v;
read(u),read(v);
for(int j = 1;j <= 3;j ++)
Link(u + 3 * M,(v - 1) * 3 + j);
}
N = N + 3 * M;
Ans = 0;
for(int i = N;i;i --)
if (!Match[i]) Ans += Aug(i);
printf("%d\n", Ans - (N - 3 * M));
for(int i = 3 * M + 1;i <= N;i ++)
printf("%d%c", (Match[i] - 1) / 3 + 1,i == N ? '\n' : ' ');
}
int main()
{
freopen("npc.in","r",stdin),freopen("npc.out","w",stdout);
int T;
scanf("%d", &T);
for(;T;T --) Work();
return 0;
}