题目描述:
题目分析:
我辛辛苦苦打了一发带花树+Dinic:
#include<bits/stdc++.h>
#define maxn 1<<17
#define maxm 15000005
using namespace std;
int n,N,k,m,bit[maxn],id[maxn];
int mat[maxn];
vector<int>A,B;
namespace Blossom{
int F[maxn],typ[maxn],pre[maxn],q[maxn],L,R,vis[maxn],tim;
int fir[maxn],nxt[maxm],to[maxm],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
int find(int x){return !F[x]?x:F[x]=find(F[x]);}
int LCA(int u,int v){
for(++tim;;swap(u,v)) if(u){
if(vis[u=find(u)]==tim) return u;
vis[u]=tim,u=pre[mat[u]];
}
}
void blossom(int u,int v,int tp){
while(find(u)!=tp){
pre[u]=v,v=mat[u];
if(typ[v]==2) typ[q[++R]=v]=1;
if(find(u)==u) F[u]=tp;
if(find(v)==v) F[v]=tp;
u=pre[v];
}
}
void aug(int s){
for(int i:A) F[i]=typ[i]=pre[i]=0;
typ[q[L=R=1]=s]=1;
while(L<=R){
int u=q[L++];
for(int i=fir[u],v;i;i=nxt[i]) if(typ[v=to[i]]!=2&&find(u)!=find(v)){
if(!typ[v]){
typ[v]=2,pre[v]=u;
if(mat[v]) typ[q[++R]=mat[v]]=1;
else {while(v) {int t=mat[pre[v]]; mat[mat[v]=pre[v]]=v,v=t;} return;}
}
else {int lca=LCA(u,v); blossom(u,v,lca),blossom(v,u,lca);}
}
}
}
}
namespace Dinic{
const int N = 50005;
int S,T,dis[N],q[maxn],L,R,fir[N],cur[N],nxt[maxm],to[maxm],c[maxm],tot=1;
inline void line(int x,int y){
nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y,c[tot]=1;
nxt[++tot]=fir[y],fir[y]=tot,to[tot]=x,c[tot]=0;
}
void init(int sz){
S=0,T=sz+1,memset(fir,0,(T+1)<<2),tot=1;
}
bool bfs(){
memset(dis,-1,(T+1)<<2),q[L=R=1]=T,dis[T]=0;
while(L<=R){
int u=q[L++];
for(int i=fir[u],v;i;i=nxt[i]) if(c[i^1]&&dis[v=to[i]]==-1) dis[v]=dis[u]+1,q[++R]=v;
}
return ~dis[S];
}
int aug(int u,int augco){
if(u==T) return augco;
int need=augco,delta;
for(int &i=cur[u];i;i=nxt[i]) if(c[i]&&dis[to[i]]+1==dis[u]){
delta=aug(to[i],min(c[i],need)),c[i]-=delta,c[i^1]+=delta;
if(!(need-=delta)) break;
}
return augco-need;
}
void dinic(){
while(bfs()) memcpy(cur,fir,(T+1)<<2),aug(S,1e9);
for(int i=1,sz=A.size();i<=sz;i++) for(int j=fir[i];j;j=nxt[j]) if(!c[j]&&to[j]) mat[A[i-1]]=B[to[j]-sz-1],mat[B[to[j]-sz-1]]=A[i-1];
}
}
using Dinic::S; using Dinic::T;
inline void print(int x,int y){
printf("%d ",1+bool(y));
for(int i=0;i<n;i++) if(x>>i&1) putchar(i+'a');
if(y) {putchar(' ');for(int i=0;i<n;i++) if(y>>i&1) putchar(i+'a');}
putchar('\n');
}
int main()
{
scanf("%d%d",&n,&k),N=1<<n;
for(int i=1;i<N;i++) bit[i]=bit[i>>1]+(i&1);
for(int t=1;t<=k/2;t++){
A.clear(),B.clear(); int sA=0,sB=0;
for(int i=1;i<N;i++) if(bit[i]==t) A.push_back(i),id[i]=++sA;
for(int i=N-1;i>=1;i--) if(bit[i]==k-t) B.push_back(i),id[i]=sA+(++sB);
for(int i:A) if(!mat[i])
for(int j:B) if(!mat[j]&&!(i&j)){
mat[i]=j,mat[j]=i; break;
}
if(t*2==k){
for(int i:A) for(int j:B) if(!(i&j)) Blossom::line(i,j);
for(int i:A) if(!mat[i]) Blossom::aug(i);
}
else{
Dinic::init(sA+sB);
for(int i:A) if(!mat[i]) Dinic::line(S,id[i]); else Dinic::line(id[i],S);
for(int i:B) if(!mat[i]) Dinic::line(id[i],T); else Dinic::line(T,id[i]);
for(int i:A){
int s=N-1-i;
for(int j=s;j;j=(j-1)&s) if(bit[j]==k-t) mat[i]==j?Dinic::line(id[j],id[i]):Dinic::line(id[i],id[j]);
}
Dinic::dinic();
}
}
int ans=0;
for(int i=1;i<N;i++) if(bit[i]<=k&&i>mat[i]) ans++;
printf("%d\n",ans);
for(int i=1;i<N;i++) if(bit[i]<=k&&i>mat[i]) print(i,mat[i]);
}
然后被随机匈牙利爆c。。
example(Code by LanrTabe):
#include <bits/stdc++.h>
const int N=1<<17;
std::mt19937 Rand(0721);
int n,k,Mat[N],Vis[N];
std::vector<int> v[20],G[N];
std::vector<std::pair<int,int> > Ans;
inline void Out(int x){for(int i=0;i<n;++i)if(x>>i&1)putchar('a'+i);}
bool DFS(int x)
{
std::shuffle(G[x].begin(),G[x].end(),Rand),Vis[x]=1;
for(int i=0,y,v;i<(int)G[x].size();++i)if(!Vis[Mat[y=G[x][i]]])
{
if(v=Mat[y],Mat[x]=y,Mat[y]=x,!v||DFS(v))return true;
Mat[v]=y,Mat[y]=v,Mat[x]=0;
}
return false;
}
void Link(std::vector<int>& L,int v,int s,int c,int r){
if(r>=0&&r+c<=n)c!=n?Link(L,v,s,c+1,r),s>>c&1?Link(L,v|1<<c,s,c+1,r-1):void():L.push_back(v);}
void Match(std::vector<int>& u,std::vector<int>& v)
{
std::vector<int> s;
s.reserve(u.size()+v.size());
for(int i:u)s.push_back(i);
for(int i:v)s.push_back(i);
for(int i:s)Link(G[i],0,((1<<n)-1)^i,0,k-__builtin_popcount(i));
for(int c;;)
{
std::shuffle(s.begin(),s.end(),Rand),c=0;
for(int i:s)Vis[i]=0;
for(int i:s)if(!Mat[i])DFS(i);
for(int i:u)c+=!Mat[i];
if(!c||(&u==&v&&c==int(u.size()&1)))break;
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1,j;i<1<<n;++i)if((j=__builtin_popcount(i))<=k)v[j].push_back(i);
for(int i=1;i<=k-i;++i)Match(v[i],v[k-i]);
for(int i=1;i<1<<n;++i)if(__builtin_popcount(i)<=k)
{if(Mat[i]>i)Ans.emplace_back(i,Mat[i]);
else if(!Mat[i])Ans.emplace_back(i,0);}
printf("%d\n",(int)Ans.size());
for(auto i:Ans)
{
printf("%d ",1+(i.second>0)),Out(i.first),putchar(i.second?' ':'\n');
if(i.second)Out(i.second),putchar('\n');
}
return 0;
}
然而还有更快更短的神奇暴力更换匹配(%Freopen):
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
int n,K,bit[maxn],mat[maxn];
vector<int>G[20];
vector<vector<int> >ans;
void print(int x){
for(int i=0;i<n;i++) if(x>>i&1) putchar('a'+i);
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%d%d",&n,&K);
for(int i=1;i<(1<<n);i++){
bit[i] = bit[i>>1] + (i&1);
G[bit[i]] .push_back(i);
}
for(int i=0;i<=K-i;i++){
set<int>st;
for(int j=0;j<G[i].size();j++)
st.insert(G[i][j]);
// random_shuffle(G[K-i].begin(),G[K-i].end());
int l = 0;
for(int u;!st.empty();){
if(i == K-i && st.size() == 1) break;
u=*st.rbegin();
for(;;l++){
if(l == G[K-i].size()) l = 0;
if((G[K-i][l] & u) == 0){
int v = G[K-i][l];
if(mat[v]) mat[mat[v]] = 0 , st.insert(mat[v]);
else st.erase(v);
mat[u] = v , mat[v] = u;
st.erase(u);
l++;
break;
}
}
}
}
for(int i=1;i<(1<<n);i++) if(bit[i] <= K){
if(mat[i]){
if(mat[i] > i){
vector<int>r;
r.push_back(i),r.push_back(mat[i]);
ans.push_back(r);
}
}
else{
vector<int>r;
r.push_back(i);
ans.push_back(r);
}
}
printf("%d\n",ans.size());
for(int i=0;i<ans.size();i++){
printf("%d",ans[i].size());
for(int j=0;j<ans[i].size();j++)
putchar(' '),print(ans[i][j]);
puts("");
}
}