• cf 11D A Simple Task(状压DP)


    题意:

    N个点构成的无向图,M条边描述这个无向图。

    问这个无向图中共有多少个环。

    (1 ≤ n ≤ 19, 0 ≤ m

     

    思路:

    例子:

    4 6

    1 2

    1 3

    1 4

    2 3

    2 4

    3 4

    答案:7

    画个图发现,直接暴力DFS有太多的重复计算。用DP。

    枚举点数(状态),每个状态的起点、终点(起点可以不用枚举,因为反正是一个环,谁作为起点都一样)。

    dp[S][i]:状态是S,i是终点   含义:从S中的第一个数s出发到达第i个点的方案数。如果s和i相加,总方案数ans+=dp[S][i]

    dp[S][i]=sigma(dp[S'][i'])  S'是去掉第i个点后的点集,i'属于S'且i'和i相连。

    *结果除以2的原因:例:1-2-3-4-1   实际上和1-4-3-2-1是一样的。

    代码:

    int n,m;
    char G[25][25];
    int S[1<<19]; //全局状态
    int cnS;
    int P[25]; //全局指针
    int cnP;
    ll dp[(1<<19)+5][25];
    ll ans;
    
    
    
    void finds(int nn,int fNum,int nowNum,int nowPos,int Ss){ //长度为nn,共要放fNum个,现在已放nowNum个,现在正在nowPos位置要进行第nowNum+1个放置的尝试
        if(nowNum==fNum){
            S[++cnS]=Ss;
            return;
        }
        int t1=fNum-nowNum;
        rep(i,nowPos,nn-t1+1){
            int nSs=Ss+(1<<(i-1));
            finds(nn,fNum,nowNum+1,i+1,nSs);
        }
    }
    void calc(int nn,int S){ //总长度为nn,计算状态S哪些位置上为1,存在全局指针P【】中。
        cnP=0;
        rep(i,1,nn){
            int t=(1<<(i-1));
            if((S&t)>0){
                P[++cnP]=i;
            }
        }
    }
    void init(){
        cnS=0;
        cnP=0;
        finds(n,2,0,1,0);
        mem(dp,0);
    
        rep(i,1,cnS){
            int ss=S[i];
            calc(n,ss);
            rep(j,2,cnP){
                if(G[P[1]][P[j]]==1){
                    dp[ss][P[j]]=1;
                }
            }
        }
    }
    void solve(){
        rep(i,3,n){ //状态由i个点构成
            cnS=0;
            cnP=0;
            finds(n,i,0,1,0);
            rep(tt,1,cnS){
                int ss=S[tt];
                calc(n,ss);
                rep(j,2,cnP){
                    int pj=P[j]; //终点
                    int nss=ss-(1<<(pj-1)); //上一个状态
                    rep(k,2,cnP){ //枚举终点
                        if(k==j) continue;
                        if(G[pj][P[k]]==0) continue;
                        int pk=P[k];
                        dp[ss][pj]+=dp[nss][pk];
                    }
                    if(G[P[1]][pj]==1){
                        ans+=dp[ss][pj];
                    }
                }
            }
        }
    }
    
    
    
    int main(){
        cin>>n>>m;
    
        mem(G,0);
        while(m--){
            int a,b;
            scanf("%d%d",&a,&b);
            G[a][b]=G[b][a]=1;
        }
    
        if(n==1 || n==2){
            puts("0");
        }
        else{
            init();
            ans=0;
            solve();
            printf("%I64d
    ",ans/2);
        }
    
        return 0;
    }
  • 相关阅读:
    localX mouseX stageX
    帮陈云庆做的手机报
    另一种换行排列方块的方法
    换行排列(思路源自陈勇源代码)
    网上摘的
    ASP.NET页面间数据传递(转)
    数据库连接字符串大全 之 SQL服务器篇
    保存一个免费的在线的图片转换工具网站,支持BMP,JPG,IOC,PNG和GIF
    关于IE6和IE7以及多个版本IE共存的问题
    如何测试sql语句性能,提高执行效率
  • 原文地址:https://www.cnblogs.com/fish7/p/4309751.html
Copyright © 2020-2023  润新知