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,因为这个环你从左边开始排和从右边开始排石一样的。

 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
",ans);
47     }
48     return 0;
49 }
View Code
原文地址:https://www.cnblogs.com/bin-gege/p/5701591.html