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的主要内容,如果未能解决你的问题,请参考以下文章
CodeForces - 11D A Simple Task