首页 > 其他 > 详细

状压dp好题.....算把..

时间:2020-02-05 23:39:33      阅读:96      评论:0      收藏:0      [点我收藏+]

http://codeforces.com/problemset/problem/11/D

 

题意很明确了  找多少个简单环

 

首先考虑环怎么找

 

简单的会想到  用状态压缩dp的方法

F[S][I]已经走过了S集合,且结束在I点的方案树

当出现一个环时,头尾一定相连,此时结束点以及可以表示出来了

考虑如何判断首尾相连,以及对于一个环来说,可能存在重复,这两个问题怎么解决

前面这个有点恶心,看一下后面这个怎么解决

这个重复问题,一般是固定一个点,然后再搞

那么问题来了固定那个点为起始点呢??

不失一般性的,我们以集合中lowbit位置的点作为起点

那么很显然,起点和终点都有了

可以愉快的进行dp了

 

又因为是无向图

显然有一条边别搞做一个环的情况,和环转的顺序不同的情况

于是答案要做相应处理....

 

到这里再仔细想想怎么写,过一过

 

经验:嘛,做题最好把已知问题罗列出来,然后(会发现可以帮助思考....(当然抄题解也是不错选择))

还有就是要考虑答案的不完全性

 

 

技术分享图片
#include<bits/stdc++.h>
using namespace std;

long long n,m,ans=0;
long long tu[25][25];
long long f[1<<20][20];

int main(){
    memset(tu,0x7f,sizeof(tu));
    memset(f,0,sizeof(f));
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        long long x,y;
    cin>>x>>y,tu[x-1][y-1]=tu[y-1][x-1]=1;         
    }
    for(int i=0;i<n;i++)f[1<<i][i]=1;
    for(int S=0;S<(1<<n);S++){
        for(int i=0;i<n;i++){
            if(!f[S][i])continue;
            for(int j=0;j<n;j++){
                if(((1<<j)<(S&(-S)))||tu[i][j]!=1)continue;
                if((1<<j)&S){
                    if((1<<j)==(S&(-S)))ans+=f[S][i];    
                }
                else{
                    f[S|(1<<j)][j]+=f[S][i];
                }
            }
        }
    }
    cout<<(ans-m)/2<<endl;
}
View Code

 

状压dp好题.....算把..

原文:https://www.cnblogs.com/shatianming/p/12266887.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!