CF11D A Simple Task 状压DP

Posted itst

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF11D A Simple Task 状压DP相关的知识,希望对你有一定的参考价值。

传送门


(N leq 19)……

不难想到一个状压:设(f_{i,j,k})表示开头为(i)、结尾为(j)、经过的点数二进制下为(k)的简单路总数,贡献答案就看(i,j)之间有没有边。

当然,会有一些问题:①路会算重;②(2^NN^2)的数组开不下(当然②才是重点),所以考虑优化算法

考虑类似最小环的优化

(f_{i,j})表示开头为(log_2lowbit(j)),结尾为(i),经过的点数二进制下为(j)的简单路总数,转移跟上面类似,值得注意的是对于(f_{k,j | 2^k} leftarrow f_{i,j})还需要保证(k > log_2lowbit(j)),否则状态中一条简单路的开头会变

当然这样子每一条路还是会被算(2)遍,每一条边也会产生(1)的贡献,最后减掉就可以了。

#include<bits/stdc++.h>
#define lowbit(x) ((x) & -(x))
#define low(x) (int)(log2(lowbit(x)) + 0.1)
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c)){
        if(c == ‘-‘)
            f = 1;
        c = getchar();
    }
    while(isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ ‘0‘);
        c = getchar();
    }
    return f ? -a : a;
}

bool Edge[19][19];
int head[19] , ind[1 << 19];
int N , M;
long long dp[19][1 << 19] , ans;

int main(){
    #ifndef ONLINE_JUDGE
    //freopen("in" , "r" , stdin);
    //freopen("out" , "w" , stdout);
    #endif
    N = read();
    M = read();
    for(int i = 1 ; i <= M ; ++i){
        int a = read() - 1 , b = read() - 1;
        Edge[a][b] = Edge[b][a] = dp[max(a , b)][(1 << a) + (1 << b)] = 1;
    }
    for(int i = 1 ; i < 1 << N ; ++i)
        for(int j = 0 ; j < N ; ++j)
            if(dp[j][i] && i & (1 << j)){
                ans += Edge[low(i)][j] * dp[j][i];
                for(int k = low(i) + 1 ; k < N ; ++k)
                    if(Edge[j][k] && !(i & (1 << k)))
                        dp[k][i | (1 << k)] += dp[j][i];
            }
    cout << (ans - M) / 2;
    return 0;
}

以上是关于CF11D A Simple Task 状压DP的主要内容,如果未能解决你的问题,请参考以下文章

CF11D A Simple Task

CF 11D A Simple Task 题解

题解 CF11D A Simple Task

CodeForces - 11D A Simple Task

[CodeForces 11D] A Simple Task - 状态压缩入门

CodeForces 11D A Simple Task