今天听完派队的教学
感觉又可以水几道紫题了
好耶✌
不过想起ygg提到的记忆化搜索
自己其实也是没有搞懂的
还是去做了几道题吧
紫题喵
最开始想的是一个这样的状态
f[i][j] 表示的是 第i块板子 前一块用的是编号为j的颜色
其实我们仔细想想就可以想出来 这个状态表示是有会漏情况的 比如1为头的时候
我们再搜3的时候 后面有的情况是有的 但是我们就直接返回了
后来被他们讲到 这就是有后效性 意会一下
一个可做的做法
我们观察道c1 的数据范围奇小无比 并且抽象一下可以用ci的大小来划分成5种集合
非常牛逼!
这样我们就可以写出状态转移方程:
f[c1][c2][c3][c4][c5][last]=
[c_1 - (last == 2)] * f[c_1 - 1][c_2][c_3[c_4][c_5][1] +[c1−(last==2)]∗f[c1−1][c2][c3[c4][c5][1]+
[c_2 - (last == 3)] * f[c_1 + 1][c_2 - 1][c_3][c_4][c_5][2] +[c2−(last==3)]∗f[c1+1][c2−1][c3][c4][c5][2]+
[c_3 - (last == 4)] * f[c_1][c_2 + 1][c_3 - 1][c_4][c_5][3] +[c3−(last==4)]∗f[c1][c2+1][c3−1][c4][c5][3]+
[c_4 - (last == 5)] * f[c_1][c_2][c_3 + 1][c_4 - 1][c_5][4] +[c4−(last==5)]∗f[c1][c2][c3+1][c4−1][c5][4]+
c_5 * f[c_1][c_2][c_3][c_4 + 1][c_5 - 1][5]c5∗f[c1][c2][c3][c4+1][c5−1][5]
这样子确实是不重不漏的
我们可以这样子理解记忆化搜索:
我们就是在爆搜 但是加了一个不重不漏的集合 来优化
下面的dfs 也是很符合爆搜
就像是在枚举这一位到底填啥 让后根据填的啥规定系数
- #include
- using namespace std;
- const int N = 20;
- const int M = 1<<16;
- const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int n,f[16][16][16][16][16][6],t[6];
- int dfs(int a,int b,int c,int d,int e,int last){
- int &v=f[a][b][c][d][e][last];
- if(v)return v;
- if(!a&&!b&&!c&&!d&&!e)return 1;
- int cnt=0;
- if(a) cnt=(cnt+(a-(last==2))*dfs(a-1,b,c,d,e,1))%mod;
- if(b) cnt=(cnt+(b-(last==3))*dfs(a+1,b-1,c,d,e,2))%mod;
- if(c) cnt=(cnt+(c-(last==4))*dfs(a,b+1,c-1,d,e,3))%mod;
- if(d) cnt=(cnt+(d-(last==5))*dfs(a,b,c+1,d-1,e,4))%mod;
- if(e) cnt=(cnt+e*dfs(a,b,c,d+1,e-1,5))%mod;
- v=cnt%mod;
- return v;
- }
- signed main(){
- fast
- cin>>n;
- for(int i=1;i<=n;i++){
- int x;cin>>x;
- t[x]++;
- }
- cout<<dfs(t[1],t[2],t[3],t[4],t[5],0)<
- return ~~(0^_^0);
- }
P4850 [IOI2009] 葡萄干 raisins
我们首先来考虑状态如何表示
数据范围只有50 并且切的刀数也是固定的
状态表示就4维就好了 f[x1][x2][y1][y2]表示矩阵类的min 吧
这里和动态规划差不多 属性不一样 dfs 过程也不一样 cnt+= min枚举取min
那我们在考虑爆搜咋写 其实就是枚举横着切 在哪切 竖着在哪切 最后加上自己当前大小的sum
- #include
- using namespace std;
- const int N = 55;
- const int M = 1<<16;
- const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int n,m,f[N][N][N][N],sum[N][N];
- int dfs(int x1,int x2,int y1,int y2){
- if(f[x1][x2][y1][y2])return f[x1][x2][y1][y2];
- if(x1==x2&&y1==y2)return 0;
- f[x1][x2][y1][y2]=inf;
- int cut=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];
- for(int i=x1;i
- f[x1][x2][y1][y2]=min(f[x1][x2][y1][y2],dfs(x1,i,y1,y2)+dfs(i+1,x2,y1,y2));
- }
- for(int i=y1;i
- f[x1][x2][y1][y2]=min(f[x1][x2][y1][y2],dfs(x1,x2,y1,i)+dfs(x1,x2,i+1,y2));
- }
- f[x1][x2][y1][y2]+=cut;
- return f[x1][x2][y1][y2];
- }
- signed main(){
- fast
- cin>>n>>m;
- for(int i=1;i<=n;i++){
- for(int j=1;j<=m;j++){
- int x;cin>>x;
- sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+x;
- }
- }
- cout<<dfs(1,n,1,m)<
- return ~~(0^_^0);
- }
P3609 [USACO17JAN]Hoof, Paper, Scissor G
哦 这道题不是记忆化搜索
但是他tag写的记忆化搜索
并且题解也全是记忆化搜索
但是我一眼就是dp啊
就很普通的一个dp
f[i][j][k] 表示我们现在是第i个手势 我们变化了j次 并且上次手势是k
时间复杂度就是O(1e5*20*3) 完全可以通过这道题
- #include
- using namespace std;
- const int N = 1e5+10;
- const int M = 1<<16;
- const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int a[N],f[N][22][3];
- signed main(){
- fast
- int n,m;cin>>n>>m;
- for(int i=1;i<=n;i++){
- char c;cin>>c;
- if(c=='H')a[i]=0;
- else if(c=='S')a[i]=1;
- else a[i]=2;
- }
- for(int i=1;i<=n;i++){
- for(int j=0;j<=m;j++){
- for(int k=0;k<3;k++){
- int k1,k2;
- if(k==0) k1=1,k2=2;
- else if(k==1) k1=0,k2=2;
- else k1=0,k2=1;
- if(k-a[i]==-1||(k==2&&a[i]==0))f[i][j][k]=max(max(f[i-1][j][k],f[i-1][j-1][k1]),f[i-1][j-1][k2])+1;
- else f[i][j][k]=max(max(f[i-1][j][k],f[i-1][j-1][k1]),f[i-1][j-1][k2]);
- }
- }
- }
- cout<<max(f[n][m][0],max(f[n][m][1],f[n][m][2]))<
- return ~~(0^_^0);
- }
P1278 单词游戏
我们来想这道题的状态表示是啥
其实这里借鉴了状态压缩二进制的思想
就是二进制拼凑
f[i][j]表示在j状态下的当前数为i的max (我们还得知道当前数是谁是吧
爆搜咋做 ?
就是枚举每一个后面的可以接的单词 over
- #include
- using namespace std;
- const int N = 1e5+10;
- const int M = 1<<16;
- //const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int f[18][M],n;
- string s[N];
- vector<int>v[300];//首字母是是啥
- int dfs(int x,int y){
- if(f[x][y])return f[x][y];
- int ans=0;
- for(auto i:v[s[x].back()]){
- if((y>>(i-1)&1)==0)ans=max(ans,dfs(i,y|(1<<(i-1))));
- }
- return f[x][y]=ans+s[x].size();
- }
- signed main(){
- fast
- cin>>n;
- for(int i=1;i<=n;i++){
- cin>>s[i];
- v[s[i][0]].push_back(i);
- }
- int ans=-2e9;
- for(int i=1;i<=n;i++)ans=max(ans,dfs(i,1<<(i-1)));
- cout<
- return ~~(0^_^0);
- }
691. 立方体IV
我这道题第一遍不是记忆化搜索做的
就是很简单的找旁边有没有他爹
有的话标记为1
然后跑一遍连续的1 就可以了 O(1e6*100)
然后题解介绍了一种记忆化搜索的方法
我们首先想状态
其实直接就是f[i] i这个点可以连多长了
我们爆搜 每一个点 要是旁边有他爹 就延续下去
这个时间复杂度是一样的
- #include
- using namespace std;
- const int N = 1e3+10;
- const int M = 1e6+10;
- const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int w[N][N];
- vector
int,int>>v[M]; - signed main(){
- fast
- int t;cin>>t;
- int tt=0;
- while(t--){
- tt++;
- int n;cin>>n;
- memset(w,0,sizeof w);
- memset(v,0,sizeof v);
- for(int i=1;i<=n;i++){
- for(int j=1;j<=n;j++){
- cin>>w[i][j];
- v[w[i][j]].emplace_back(i,j);
- }
- }
- if(n==1){
- printf("Case #%d: 1 1\n",tt);
- continue;
- }
- int a[M]={0};
- for(int i=1;i<=n*n;i++){
- auto x=v[i].back().first,y=v[i].back().second;
- if(x-1>=1&&w[x-1][y]==i+1){a[i]=1;continue;}
- if(x+1<=n&&w[x+1][y]==i+1){a[i]=1;continue;}
- if(y-1>=1&&w[x][y-1]==i+1){a[i]=1;continue;}
- if(y+1<=n&&w[x][y+1]==i+1){a[i]=1;}
- }
- int ans=0,cnt=0,num;
- for(int i=1;i<=n*n;i++){
- if(a[i])cnt++;
- else cnt=0;
- if(cnt>ans){
- num=i;
- ans=cnt;
- }
- }
- while(a[num])num--;
- printf("Case #%d: %d %d\n",tt,num+1,ans+1);
- }
- return ~~(0^_^0);
- }
记忆化搜索版
- #include
- using namespace std;
- const int N = 1e3+10;
- const int M = 1e6+10;
- const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int w[N][N],n,f[M];
- int dfs(int x,int y,int d){
- if(f[d])return f[d];
- int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
- int ans=0;
- for(int i=0;i<4;i++){
- int x1=x+dx[i],y1=y+dy[i];
- if(w[x1][y1]==d+1){
- ans=dfs(x1,y1,d+1);
- break;
- }
- }
- return f[d]=ans+1;
- }
- signed main(){
- fast
- int t;cin>>t;
- for(int C=1;t;t--,C++){
- cin>>n;
- memset(w,0,sizeof w);
- memset(f,0,sizeof f);
- for(int i=1;i<=n;i++){
- for(int j=1;j<=n;j++){
- cin>>w[i][j];
- }
- }
- int ans=0,id=0;
- for(int i=1;i<=n;i++){
- for(int j=1;j<=n;j++){
- int res=dfs(i,j,w[i][j]);
- if(res>ans){
- ans=res,id=w[i][j];
- }else if(res==ans&&id>w[i][j]){
- id=w[i][j];
- }
- }
- }
- printf("Case #%d: %d %d\n",C,id,ans);
- }
- return ~~(0^_^0);
- }
-
相关阅读:
工具学习--easyexcel-3.x 使用--写入基本使用,自定义转换--动态表头以及宽设置-
vue3_setup基础_渲染函数(ref,reactive)
[Qt]信号和槽机制
Java学习笔记:高级数据过滤
oracle查询相同条件重复值只取第1条
每日一题AC
vue3项目中引用tailwindcss与heroicons
Mac系统下TestCafe初体验
数据结构与算法编程题2
Linux中ROS话题通信中发布者基本操作(C++实现)
-
原文地址:https://blog.csdn.net/qq_23852555/article/details/126145785