hdu_5727_Necklace(二分匹配)
题目连接:hdu_5727_Necklace
题意:
有2*n个珠子,n个阳珠子,n个阴珠子,现在要将这2n个珠子做成一个项链,珠子只能阴阳交替排,有些阳珠子周围如果放了指定的阴珠子就会变坏,给你一个n和m个关系x y,这些关系指明了阳珠子x周围放y阴珠子会变坏,现在问你做成这条项链,最少变坏的阳珠子有多少个
题解:
官方题解给的是用DFS 带剪枝来做,不过我感觉那样好玄学,我的做法是将所有的阴珠子可能组成的组合全部算出来,然后用阳珠子去插空,这里插空我们要找最大的匹配,也就是我们可以用二分匹配来做,为什么要找最大匹配,因为我们要得到最少的变坏珠子,我们要找到阳珠子在不变坏的情况下最多可以放的个数。然后就是建图,
我们先把二分图的所有的边都连上,然后如果发现阳珠子在这个空会变坏,那么我们就删除这条边,最后跑匈牙利跑出来就是最大的不会变坏的阳珠子个数,然后我们维护一下每种阴珠子的排列方式下的ans,总时间复杂度为(n-1)!*n2这里n<=9,所以随便能跑过,为什么是n-1,因为这是一个环,我们可以固定其中一个点,这样可以少一个阶,当然你还可以优化到((n-1)!*n2)/2,因为这个环你从左边开始排和从右边开始排石一样的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=a;i<=b;++i) 4 using namespace std; 5 6 const int N=111; 7 int g[N],nxt[N],v[N],ed,n,m,x,y,f[11],b[11],G[11][11]; 8 9 inline void adg(int x,int y){v[++ed]=y,nxt[ed]=g[x],g[x]=ed;} 10 inline void up(int &a,int b){if(a>b)a=b;} 11 12 int find(int x,int m) 13 { 14 F(i,1,m) 15 if(G[x][i]&&!b[i]) 16 { 17 b[i]=1; 18 if(!f[i]||find(f[i],m))return f[i]=x,1; 19 } 20 return 0; 21 } 22 23 int hungry(int n,int m,int ans=0) 24 { 25 mst(f,0); 26 F(i,1,n)mst(b,0),ans+=find(i,m); 27 return ans; 28 } 29 30 int main(){ 31 while(~scanf("%d%d",&n,&m)) 32 { 33 if(n==0||m==0){puts("0");continue;} 34 mst(g,0),ed=0; 35 F(i,1,m)scanf("%d%d",&x,&y),adg(y,x); 36 int now[11],ans=1000; 37 F(i,1,n)now[i]=i; 38 do{ 39 F(i,1,n)F(j,1,n)G[i][j]=1; 40 F(ic,1,n)for(int i=g[now[ic]];i;i=nxt[i]) 41 if(ic==1)G[1][v[i]]=G[n][v[i]]=0; 42 else G[ic][v[i]]=G[ic-1][v[i]]=0; 43 up(ans,n-hungry(n,n)); 44 if(!ans)break; 45 }while(next_permutation(now+2,now+1+n)); 46 printf("%d\n",ans); 47 } 48 return 0; 49 }