HDU 3091(动态规划-状态压缩)

问题描述:

One day , Partychen gets several beads , he wants to make these beads a necklace . But not every beads can link to each other, every bead should link to some particular bead(s). Now , Partychen wants to know how many kinds of necklace he can make.

Input

It consists of multi-case . 
Every case start with two integers N,M ( 1<=N<=18,M<=N*N ) 
The followed M lines contains two integers a,b ( 1<=a,b<=N ) which means the ath bead and the bth bead are able to be linked. 

Output

An integer , which means the number of kinds that the necklace could be.

Sample Input

3 3
1 2
1 3
2 3
Sample Output

2
题目题意:给我们n棵珠,给定它们的连接规则,问有多少种项链(注意首尾相连)

题目分析:因为珠子不多,所以我们可以用数字的每一位表示珠子的状态,因为珠子的连接是有规则的,不是所有的珠子都可以相连,假设我们如果知道了前一个珠子是那个,那么后面那些珠子可以相连就确定了,所以还需要一维来表示最后一颗珠子是谁。

dp[i][j]的保存的就是在状态i下,结尾是珠子j的多少种情况。还有一点是首尾的问题,我们可以假设第一个是第一颗珠子,结果不影响,那么尾部那些就可以确定了。

代码如下:

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define ll long long
using namespace std;

ll dp[(1<<18)][20];
bool G[20][20];

int main()
{
    int n,m;
    while (scanf("%d%d",&n,&m)!=EOF) {
        memset (G,false,sizeof (G));
        for (int i=1;i<=m;i++) {
            int a,b;
            scanf("%d%d",&a,&b);
            G[a][b]=G[b][a]=true;//保存图
        }
        memset (dp,0,sizeof (dp));
        dp[1][1]=1;
        for (int i=0;i<=((1<<n)-1);i++) {
            for (int j=n;j>=1;j--) {
                if (!dp[i][j]) continue;
                for (int k=1;k<=n;k++) {
                    if (G[k][j]&&!(i&(1<<(k-1)))) dp[i|(1<<(k-1))][k]+=dp[i][j];
                }
            }
        }
        ll ans=0;
        for (int i=1;i<=n;i++) {
            if (G[1][i])//首尾相连
            ans+=dp[((1<<n)-1)][i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值