Codeforces Beta Round #11, problem: (D) A Simple Task 状态压缩DP+记忆化搜素DP

来源:互联网 发布:微领袖学堂源码 编辑:程序博客网 时间:2024/05/01 07:04

题意:在图中找简单回路

/*************看了大神的博客才有所感悟啊,记忆化搜索+状态压缩。。。。太神了...这种复杂度,近百万的DFS复杂度居然没有TLE,果然经验不足,菜鸟一只。用状态压缩枚举起点和可能经过的点。可以判定的简单通路 i->j,存在的条数为sum(i->k) 其中k,j之间有边。当然,每次计算通路个数的时候,可以借每一个k来判断回路的条数,当然只能算一次。这样加出来的回路会有重复,因为可能把顺逆两种方向运动的回路都考虑进去。记忆化搜索的好处是可以精确的计算每次遍历点的情况,而如果单纯只是循环的话,却没有这么灵活。****************/#define LL long long#include<cstdio>#include<cstring>const int LMT=22,LMS=1<<19;LL dp[LMS][LMT],ans;int n,start,tem,gra[LMT][LMT];int get_one(int x){    int res=0;    do    res+=x&1;    while(x>>=1);    return res;}int left(int x){    int d=x&(-x),res=0;    while(d>>=1)res++;    return res;}LL dfs(int mas,int end){    if(dp[mas][end]>=0)return dp[mas][end];    LL res=0;    for(int j=start;j<n;j++)    if(gra[j][end]&&((1<<j)&mas)&&(tem==2||j!=start))    {        tem--;        res+=dfs(mas^(1<<end),j);        tem++;    }    if(tem>2&&gra[end][start])        ans+=res;    dp[mas][end]=res;    return res;}int main(void){    int m,lim;    scanf("%d%d",&n,&m);    memset(dp,-1,sizeof(dp));    while(m--)    {        int u,v;        scanf("%d%d",&u,&v);        u--;v--;        gra[u][v]=gra[v][u]=1;    }    lim=1<<n;    for(int i=0;i<n;i++)dp[1<<i][i]=1;    for(int t=0;t<lim;t++)    {        start=left(t);        tem=get_one(t);        for(int j=start;j<n&&tem>1;j++)        if(gra[j][start]&&((1<<j)&t))           dfs(t,j);    }    printf("%I64d\n",ans>>1);    return 0;}


原创粉丝点击