传送门
题解:
直接对于每个瓶子的三个匹配位置建点,连成完全图。
球和瓶子该连的边全部连上。
然后跑一般图最大匹配即可。
其实也可以先跑一遍用费用流优化常数,不想写了。
费用流做法就是每个瓶子建立三个点,通过赋费用来贪心流满前缀边,然后对于2,3位置只流了一个的,单独拿出来,有相同前驱的之间连边,跑一般图最大匹配。
而费用流不可能成为复杂度瓶颈,因为SPFA和全图DFS总次数是 O ( 1 ) O(1) O(1)的,所以实际上费用流的复杂度在 O ( ( n + 3 m ) 2 ) O((n+3m)^2) O((n+3m)2)
然后就可以把跑一般图匹配的点数控制在 m 2 \frac{m}{2} 2m以内,常数会更小。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
cs int N=607;
int tot;
std::vector<int> G[N];
inline void adde(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
int pre[N],match[N],q[N],hd,tl;
int tim,tic[N],typ[N],fa[N];
inline int gf(int u){return u==fa[u]?u:(fa[u]=gf(fa[u]));}
inline void clear(){
for(int re i=1;i<=tot;++i)G[i].clear();
memset(match,0,sizeof(int)*(tot+1));
}
inline int LCA(int u,int v){
for(++tim;;std::swap(u,v))if(u){
u=gf(u);
if(tic[u]==tim)return u;
else tic[u]=tim,u=pre[match[u]];
}
}
inline void shrink(int u,int v,int p){
while(gf(u)!=p){
pre[u]=v,v=match[u];
if(typ[v]==2)typ[v]=1,q[++tl]=v;
if(gf(u)==u)fa[u]=p;
if(gf(v)==v)fa[v]=p;
u=pre[v];
}
}
inline int aug(int s){
for(int re i=1;i<=tot;++i)fa[i]=i;
memset(typ,0,sizeof(int)*(tot+1));
memset(pre,0,sizeof(int)*(tot+1));
typ[q[hd=tl=1]=s]=1;
while(hd<=tl){
int u=q[hd++];
for(int re v:G[u]){
if(gf(v)==gf(u)||typ[v]==2)continue;
else if(!typ[v]){
typ[v]=2,pre[v]=u;
if(!match[v]){
for(int re t=v,las,tp;t;t=las){
las=match[tp=pre[t]];
match[t]=tp,match[tp]=t;
}
return true;
}
typ[match[v]]=1,q[++tl]=match[v];
}
else if(typ[v]==1){
int p=LCA(u,v);
shrink(u,v,p);
shrink(v,u,p);
}
}
}
return false;
}
inline int calc(){
int ans=0;
for(int re i=1;i<=tot;++i)ans+=(!match[i]&&aug(i));
return ans;
}
int idb[N],idc[N][3];
inline void solve(){
tot=0;int n,m,e;scanf("%d%d%d",&n,&m,&e);
for(int re i=1;i<=n;++i)idb[i]=++tot;
for(int re i=1;i<=m;++i)
for(int re j=0;j<3;++j)idc[i][j]=++tot;
clear();
for(int re i=1;i<=m;++i){
adde(idc[i][0],idc[i][1]);
adde(idc[i][1],idc[i][2]);
adde(idc[i][2],idc[i][0]);
}
while(e--){
int u,v;scanf("%d%d",&u,&v);
adde(idb[u],idc[v][0]);
adde(idb[u],idc[v][1]);
adde(idb[u],idc[v][2]);
}
std::cout<<calc()-n<<"\n";
for(int re i=1;i<=n;++i)std::cout<<(match[i]-n-1)/3+1<<" ";
std::cout<<"\n";
}
signed main(){
#ifdef zxyoi
// freopen("NPC.in","r",stdin);
#endif
int T;scanf("%d",&T);
while(T--)solve();
return 0;
}