\(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;
}
原文地址:https://www.cnblogs.com/Itst/p/10321517.html
时间: 2024-10-15 20:25:54