传送门
题意:有nnn个球和mmm个筐,每个筐最多放333个球,每个球只能放入特定的一些筐中,在题中给出。构造一种放球的方案使得nnn个球都被放在某个筐中且 球的个数不超过111 的筐的数量尽量大。
m≤100,n≤3mm\leq 100,n\leq 3mm≤100,n≤3m
把每个筐拆成 333 个点,并每个筐的三个点两两之间连边。
每个球和可以放的筐的三个点都连上边。
然后跑一般图最大匹配。
这样如果一个筐的333个点被匹配的点不超过111,可以找两个点自己匹配。
而每个球都可以且必须找一个匹配,所以最终答案是最大匹配−n最大匹配-n最大匹配−n
一个很坑的地方,最大匹配的时候球不一定都有匹配,输出方案时会出锅。解决方法是先从球开始增广,这样每个球先找到匹配点,这样最后一定有匹配。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <queue>
#include <cassert>
#define MAXN 1005
#define MAXM 1000005
using namespace std;
inline int read()
{int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
struct edge{int u,v;}e[MAXM];
int head[MAXN],nxt[MAXM],cnt;
void addnode(int u,int v)
{e[++cnt]=(edge){u,v};nxt[cnt]=head[u];head[u]=cnt;
}
inline void insert(int u,int v){addnode(u,v),addnode(v,u);}
int mat[MAXN],pre[MAXN],col[MAXN],fa[MAXN],N;
int idx[MAXN],tot;
int find(const int& x){return fa[x]==x? x:fa[x]=find(fa[x]);}
queue<int> q;
inline int lca(int x,int y)
{for (++tot;;swap(x,y))if (x){x=find(x);if (idx[x]==tot) return x;idx[x]=tot,x=pre[mat[x]];}
}
inline void shrink(int x,int y,int l)
{while (find(x)!=l){pre[x]=y,y=mat[x];if (col[y]==2) col[y]=1,q.push(y);if (x==find(x)) fa[x]=l;if (y==find(y)) fa[y]=l;x=pre[y];}
}
inline int bfs(int s)
{for (int i=1;i<=N;i++) pre[i]=col[i]=0,fa[i]=i;col[s]=1;while (!q.empty()) q.pop();q.push(s);while (!q.empty()){int u=q.front();q.pop();for (int i=head[u];i;i=nxt[i]){int v=e[i].v;if (find(u)==find(v)||col[v]==2) continue;if (!col[v]){col[v]=2,pre[v]=u;if (!mat[v]){for (int las;v;v=las)las=mat[pre[v]],mat[v]=pre[v],mat[pre[v]]=v;return 1;}col[mat[v]]=1,q.push(mat[v]);}else{int l=lca(u,v);shrink(u,v,l),shrink(v,u,l);}}}return 0;
}
int main()
{for (int T=read();T;T--){memset(head,0,sizeof(head));memset(nxt,0,sizeof(nxt));cnt=0;memset(mat,0,sizeof(mat));tot=0;memset(idx,0,sizeof(idx));int n,m,e;n=read(),m=read(),e=read();N=3*m+n;for (int i=1;i<=m;i++) insert(i,i+m),insert(i,i+2*m),insert(i+m,i+2*m);for (int i=1;i<=e;i++){int v,u;v=read(),u=read();insert(3*m+v,u);insert(3*m+v,u+m);insert(3*m+v,u+2*m);}int ans=0;for (int i=N;i>=1;i--)if (!mat[i])ans+=bfs(i);printf("%d\n",ans-n);for (int i=3*m+1;i<=N;i++) printf("%d%c",(mat[i]-1)%m+1," \n"[i==N]);}return 0;
}