contest 0820 calc [DP][记忆化搜索]

contest 0820 calc [DP][记忆化搜索]

当时竟然不知道暴力怎么打,于是就只骗了5分 Q^Q

50pts

先把每种合法的边(端点编号差<=lim的边)放到一个数组里面,然后暴搜,最后判断选出来的边构成的图是否合法(每个点的度数都是偶数)
期望得分:40~50pts

100pts

状压DP

我们强制规定边都有方向(从编号大的指向编号小的;也可以反着来)。用 f[u][v][k][s] f [ u ] [ v ] [ k ] [ s ] 表示从 u u 指向v,剩余 k k 条边可用,且编号为[ulim+1,u]的点的度数奇偶状态为s(设1为奇,0为偶)。

每次有两种转移: u u v之间再连一条边; u u v之间不连边,向 v1 v − 1 连一条边。

对于第一种转移,只要还有边可以选就可行。

对于第二种转移:

  • 如果有 v1 v − 1 这个点且 v1 v − 1 u u 的差<=lim,那么就可以向 f[u][v1][k][s] f [ u ] [ v − 1 ] [ k ] [ s ′ ] 转移

  • 如果上述转移不可行,那么说明能够与 u u 相连的点已经讨论完了,要开始讨论u1号点了;如果 u u 号点的度数为偶数,就可以向u1号点转移,即 f[u1][u2][k][s] f [ u − 1 ] [ u − 2 ] [ k ] [ s ′ ]

代码

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值