题目大概说有n个yang珠子n个yin珠子,要交替串成一个环形项链,有些yang珠子和某个yin珠子相邻这个yang珠子会不高兴,问最少有几个yang珠子不高兴。
自然会想到直接用状压DP去解,转移很烦,也没写出来。标程是搜索不明觉厉。。听闻了可以枚举一边的顺序,8!,然后用最大匹配解决。
然后想到的是枚举yang的顺序,然后对于每一个yang去其匹配下一个的yin,即X部是yang,而Y部是yin。不过这样开头那个yang可能出现少算的情况。。这个搞了好久都不行。。
其实,枚举yin的顺序,X部是各个yang,而Y部是位置!然后问题就引刃而解。我太菜了。。
另外用最大流超时了,然后用了个匈牙利过了,O((n-1)!*n3)的时间复杂度。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n,map[22][22],mat[22]; 7 bool used[22]; 8 bool crosspath(int k){ 9 for(int i=1; i<=map[k][0]; ++i){ 10 int j=map[k][i]; 11 if(!used[j]){ 12 used[j]=true; 13 if(mat[j]==0 || crosspath(mat[j])){ 14 mat[j]=k; 15 return true; 16 } 17 } 18 } 19 return false; 20 } 21 22 int hungary(){ 23 int res=0; 24 for(int i=1; i<=n; ++i){ 25 memset(used,0,sizeof(used)); 26 if(crosspath(i)) ++res; 27 } 28 return res; 29 } 30 31 bool rel[11][11]; 32 int main(){ 33 int m; 34 while(~scanf("%d%d",&n,&m)){ 35 memset(rel,0,sizeof(rel)); 36 int a,b; 37 while(m--){ 38 scanf("%d%d",&a,&b); 39 rel[a][b]=1; 40 } 41 42 if(n==1 && rel[1][1]){ 43 puts("1"); 44 continue; 45 } 46 if(n<=1){ 47 puts("0"); 48 continue; 49 } 50 51 int seq[11]; 52 for(int i=1; i<=n; ++i){ 53 seq[i]=i; 54 } 55 56 int res=0; 57 do{ 58 for(int i=1; i<=2*n; ++i) map[i][0]=0; 59 memset(mat,0,sizeof(mat)); 60 for(int i=1; i<=n; ++i){ 61 for(int j=1; j<=n; ++j){ 62 if(rel[i][seq[j]] || rel[i][seq[j%n+1]]) continue; 63 map[i][++map[i][0]]=j+n; 64 map[j+n][++map[j+n][0]]=i; 65 } 66 } 67 res=max(res,hungary()); 68 }while(next_permutation(seq+2,seq+1+n)); 69 printf("%d ",n-res); 70 } 71 return 0; 72 }