【题解】 CF11D A Simple Task
【题解】 CF11D A Simple Task
\(n \le 20\) 考虑状态压缩\(dp\)。
考虑状态,\(dp(i,j,O)\)表示从\(i\)到\(j\)经过点集\(O\)的路径有多少。
\(dp(i,j,O \bigcup i)=\Sigma dp(i,p,O)\),\(j-p\)有一条边。
考虑内存,我们可以认定状态压缩串中\(lowbit(x)\)位是一条路的起点,这样我们直接省掉一维。空间限制卡进去了。
考虑答案怎么统计,就是\((\Sigma (dp(i,j,O)+dp(j,i,O))-m) \div2\)
然后就是神仙一般的代码,orz Van
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<bitset>
#include<vector>
#include<map>
#include<ctime>
#include<cstdlib>
#include<set>
#include<bitset>
#include<stack>
#include<list>
#include<cmath>
using namespace std;
#define RP(t,a,b) for(register ll (t)=(a),edd_=(b);t<=edd_;++t)
#define DRP(t,a,b) for(register ll (t)=(a),edd_=(b);t>=edd_;--t)
#define ERP(t,a) for(int t=head[a];t;t=e[t].nx)
#define Max(a,b) ((a)<(b)?(b):(a))
#define Min(a,b) ((a)<(b)?(a):(b))
#define TMP template<class ccf>
#define lef L,R,l,mid,pos<<1
#define rgt L,R,mid+1,r,pos<<1|1
#define midd register int mid=(l+r)>>1
#define chek if(R<l||r<L)return
#define all 1,n,1
#define pushup(x) seg[(x)]=seg[(x)<<1]+seg[(x)<<1|1]
#define lowbit(x) ((x)&(-(x)))
typedef long long ll;
TMP inline ccf qr(ccf k){
char c=getchar();
ccf x=0;
int q=1;
while(c<48||c>57)
q=c==45?-1:q,c=getchar();
while(c>=48&&c<=57)
x=x*10+c-48,c=getchar();
if(q==-1)
x=-x;
return x;
}
const int maxn=20;
const ll mod=1e9+7;
bool e[maxn][maxn];
ll dp[maxn][1<<maxn];
ll ans;
int n,m;
int main(){
#ifndef ONLINE_JUDGE
freopen("hamilton.in","r",stdin);
freopen("hamilton.out","w",stdout);
#endif
n=qr(1);
m=qr(1);
const int maxw=(1<<n)-1;int t1,t2;
RP(t,1,m){
t1=qr(1)-1;
t2=qr(1)-1;
e[t1][t2]=1;
e[t2][t1]=1;
//dp[t1][(1<<t1)|(1<<t2)]=1;
//dp[t2][(1<<t1)|(1<<t2)]=1;
}
RP(t,0,n-1)
dp[t][(1<<t)]=1;//lowbit(x)是一个路径的起点
RP(k,0,maxw){
RP(t,0,n-1){//起点
RP(i,0,n-1){//目标点
if(e[t][i]){
if(lowbit(k)>(1<<i))
continue;
if((1<<i)&k){
if((1<<i)==lowbit(k))
ans+=dp[t][k];
}
else
dp[i][k|(1<<i)]+=dp[t][k];
}
}
}
}
printf("%lld\n",((ans-m)>>1));
return 0;
}
博客保留所有权利,谢绝学步园、码迷等不在文首明显处显著标明转载来源的任何个人或组织进行转载!其他文明转载授权且欢迎!