HDU 5727 Necklace

题目:Necklace

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5727

题意:要用n个阳石和n个阴石来串一个项链(环状),规定阳石旁边只能是阴石,阴石旁只能是阳石,现在有m对特殊阴阳石,这些阴阳石相邻会使得阳石出故障(照样可以用),问串这个项链,至少有几个故障的阳石。

思路:

  看到题目的瞬间,莫名奇妙地就想到了二分图(阴石和阳石两个集合,又要求阴阳交错着放),有个变通就是最后并不是阴石匹配阳石,而是阳石去匹配位置,看最多几个位置能放上阳石...

  我们可以先枚举所有的阴石排法(全排列),然后用二维数组s来表示阳石i可以放在哪些位置,s[i][j]=1表示阳石i可以放在j处,前提是j的两旁没有克制阳石i的阴石。这样,位置和阳石就成了两个集合,我们要做的就是让尽量多的位置放了阳石,(这种阴石排法最终故障数就是n-位置数(最大匹配数))。这道题时间卡得很紧,有一个很重要的剪枝就是全排列过程中如果最终故障数已经为0,就return吧,就不要再尝试新的排法了。

  我的代码是勉强过的,有待改进,看到网上有个自动全排列的函数next_permutation,准备去学下,我试过,比自己深搜递归快,下面两个版本,第一个1400ms左右,第二个200ms左右,快太多了,(除了本身快以外,我还少排了一个数,因为项链是一个环,所以完全可以固定一个数的位置,这样就少了一级。)

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<vector>
 5 using namespace std;
 6 int n,m,maxt;
 7 int mp[12][12];
 8 vector<int> s[12];
 9 int b[12];
10 bool u[12];
11 bool find(int x)
12 {
13   if(u[x]) return false;
14   u[x]=1;
15   for(int j=0;j<s[x].size();j++)
16   {
17     int i=s[x][j];
18     if(b[i]==0||find(b[i]))
19     {
20       b[i]=x;
21       return true;
22     }
23   }
24   return false;
25 }
26 void solve()
27 {
28   memset(b,0,sizeof(b));
29   int co=0;
30   for(int i=1;i<=n;i++)
31   {
32     memset(u,0,sizeof(u));
33     if(find(i)) co++;
34   }
35   if(co>maxt) maxt=co;
36 }
37 bool v[12];
38 int aa[12];
39 void dfs(int ceng)
40 {
41   if(ceng==n)
42   {
43     for(int i=1;i<=n;i++) s[i].clear();
44     for(int i=0;i<n;i++)
45     {
46       int k=aa[i],kk=aa[(i-1+n)%n];
47       for(int j=1;j<=n;j++)
48       {
49         if(mp[k][j]==-1&&mp[kk][j]==-1) s[j].push_back(i);
50       }
51     }
52     solve();
53     return ;
54   }
55   for(int i=1;i<=n&&maxt!=n;i++)
56   {
57     if(v[i]==1) continue;
58     v[i]=1;
59     aa[ceng]=i;
60     dfs(ceng+1);
61     v[i]=0;
62   }
63 }
64 int main()
65 {
66   int x,y;
67   while(scanf("%d%d",&n,&m)!=EOF)
68   {
69     maxt=0;
70     memset(mp,-1,sizeof(mp));
71     while(m--)
72     {
73       scanf("%d%d",&x,&y);
74       mp[y][x]=0;
75     }
76     memset(v,0,sizeof(v));
77     dfs(0);
78     printf("%d\n",n-maxt);
79   }
80   return 0;
81 }

 

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<vector>
 5 #include<algorithm>
 6 using namespace std;
 7 int n,m,maxt;
 8 int mp[12][12];
 9 vector<int> s[12];
10 int b[12];
11 bool u[12];
12 bool find(int x)
13 {
14   if(u[x]) return false;
15   u[x]=1;
16   for(int j=0;j<s[x].size();j++)
17   {
18     int i=s[x][j];
19     if(b[i]==0||find(b[i]))
20     {
21       b[i]=x;
22       return true;
23     }
24   }
25   return false;
26 }
27 void solve()
28 {
29   memset(b,0,sizeof(b));
30   int co=0;
31   for(int i=1;i<=n;i++)
32   {
33     memset(u,0,sizeof(u));
34     if(find(i)) co++;
35   }
36   if(co>maxt) maxt=co;
37 }
38 bool v[12];
39 int aa[12];
40 void dfs(int ceng)
41 {
42   for(int i=0;i<n;i++)
43   {
44     aa[i]=i+1;
45   }
46   do
47   {
48     for(int i=1;i<=n;i++) s[i].clear();
49     for(int i=0;i<n;i++)
50     {
51       int k=aa[i],kk=aa[(i-1+n)%n];
52       for(int j=1;j<=n;j++)
53       {
54         if(mp[k][j]==-1&&mp[kk][j]==-1) s[j].push_back(i);
55       }
56     }
57     solve();
58   }while(next_permutation(aa+1,aa+n)&&maxt!=n);
59 }
60 int main()
61 {
62   int x,y;
63   while(scanf("%d%d",&n,&m)!=EOF)
64   {
65     maxt=0;
66     memset(mp,-1,sizeof(mp));
67     while(m--)
68     {
69       scanf("%d%d",&x,&y);
70       mp[y][x]=0;
71     }
72     memset(v,0,sizeof(v));
73     dfs(0);
74     printf("%d\n",n-maxt);
75   }
76   return 0;
77 }
用了next_permutation

 

posted @ 2016-07-20 22:53  hchlqlz  阅读(254)  评论(0编辑  收藏  举报