contest 0820 calc [DP][记忆化搜索]
当时竟然不知道暴力怎么打,于是就只骗了5分 Q^Q
50pts
先把每种合法的边(端点编号差<=lim的边)放到一个数组里面,然后暴搜,最后判断选出来的边构成的图是否合法(每个点的度数都是偶数)
期望得分:40~50pts
100pts
状压DP
我们强制规定边都有方向(从编号大的指向编号小的;也可以反着来)。用 表示从 指向 ,剩余 条边可用,且编号为 的点的度数奇偶状态为s(设1为奇,0为偶)。
每次有两种转移: 和 之间再连一条边; 和 之间不连边,向 连一条边。
对于第一种转移,只要还有边可以选就可行。
对于第二种转移:
如果有 这个点且 与 的差 ,那么就可以向 转移
如果上述转移不可行,那么说明能够与 相连的点已经讨论完了,要开始讨论 号点了;如果 号点的度数为偶数,就可以向 号点转移,即
代码
#include<stdio.h>
#include<cstring>
#include<iostream>
#define N 35
#define Mod 998244353
using namespace std;
int n,m,lim,f[N][N][N][513];
int Add(int x,int y){return (x+y>=Mod)?(x+y-Mod):(x+y);}
int DFS(int u,int v,int Rest,int s){
if(!Rest)return s==0;if(u==1)return 0;
if(f[u][v][Rest][s]!=-1)return f[u][v][Rest][s];
int t=0;t=Add(t,DFS(u,v,Rest-1,s^1^(1<<u-v)));
if(v>1 && u-v+1<=lim)t=Add(t,DFS(u,v-1,Rest,s));
else if(~s&1)t=Add(t,DFS(u-1,u-2,Rest,s>>1));
return f[u][v][Rest][s]=t;
}
int main(){
memset(f,-1,sizeof(f));
scanf("%d%d%d",&n,&m,&lim);
printf("%d",DFS(n,n-1,m,0));
return 0;
}