HDU 3091 Necklace <<状压dp

题意

要把一些珠子串成一串,每个珠子只可以和限制特定的别的珠子串在一起,给定珠子数量和限制条件,求能组成的不同的项链的种数。

思路

看数据范围,再加上这是有限制条件的问题求解,很容易发现是状压dp的问题。dp[i][j]表示放下第i个珠子后的状态为j(即i为前一个珠子),只要保证下一个珠子能和前一个接的上就可行。那么枚举k为下一个珠子,看是否可行即可,具体看代码。然后细节上,点的下标与dp中的状态要统一起来才不会出错。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long dp[20][1<<18];
 4 int G[20][20];//数据范围小,只需要判断是否邻接,所以矩阵很方便
 5 int main()
 6 {
 7     int n,m;
 8     while(~scanf("%d%d",&n,&m))
 9     {
10         memset(dp,0,sizeof(dp));
11         memset(G,0,sizeof(G));
12         for(int i=0,a,b;i<m;i++)
13         {
14             scanf("%d%d",&a,&b);
15             G[a][b]=G[b][a]=1;//这里没统一下标,所以后面写的时候出现了很多麻烦
16         }
17         dp[0][1]=1;//因为是个环,所以任意选取一颗珠子作为开头,此处选1
18         for(int i=1;i<(1<<n);i++)
19         {
20             for(int j=0;j<n;j++)
21             {
22                 if(dp[j][i]==0) continue;//如果此状态不可达,跳过
23                 for(int k=0;k<n;k++)
24                 {
25                     if(i&(1<<k)) continue;//如果这个珠子已经放了,跳过
26                     if(G[k+1][j+1]) dp[k][i|(1<<k)]+=dp[j][i];//如果k与j(前一个珠子)能接上,就可以状态转移
27                 }
28             }
29         }
30         long long ans=0;
31         for(int i=0;i<=n;i++)
32         {
33             if(G[1][i+1])//看最后一颗珠子与第一颗是否连的起来
34                 ans+=dp[i][(1<<n)-1];
35         }
36         printf("%lld
",ans);
37     }
38 }

后记

这题一开始用了三维dp,多了一维表示第一个珠子,然后最后再除阶乘得出答案,然而事实上由于是个环,所以从哪个珠子开始关系并不大。从这题上还是学到了很多的。

原文地址:https://www.cnblogs.com/computer-luo/p/10061659.html