日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

记忆化搜索 day48

發布時間:2023/12/8 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 记忆化搜索 day48 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天聽完派隊的教學

感覺又可以水幾道紫題了

好耶?

不過想起ygg提到的記憶化搜索

自己其實也是沒有搞懂的

還是去做了幾道題吧

?P2476 [SCOI2008]著色方案

紫題喵

最開始想的是一個這樣的狀態

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 <bits/stdc++.h> 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(){fastcin>>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)<<endl;return ~~(0^_^0); }

P4850 [IOI2009] 葡萄干 raisins

我們首先來考慮狀態如何表示

數據范圍只有50 并且切的刀數也是固定的

狀態表示就4維就好了 f[x1][x2][y1][y2]表示矩陣類的min 吧

這里和動態規劃差不多 屬性不一樣 dfs 過程也不一樣 cnt+= min枚舉取min

那我們在考慮爆搜咋寫 其實就是枚舉橫著切 在哪切 豎著在哪切 最后加上自己當前大小的sum

#include <bits/stdc++.h> 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<x2;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<y2;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(){fastcin>>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)<<endl;return ~~(0^_^0); }

P3609 [USACO17JAN]Hoof, Paper, Scissor G

哦 這道題不是記憶化搜索

但是他tag寫的記憶化搜索

并且題解也全是記憶化搜索

但是我一眼就是dp啊

就很普通的一個dp

f[i][j][k] 表示我們現在是第i個手勢 我們變化了j次 并且上次手勢是k

時間復雜度就是O(1e5*20*3) 完全可以通過這道題

#include <bits/stdc++.h> 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(){fastint 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]))<<endl;return ~~(0^_^0); }

P1278 單詞游戲

我們來想這道題的狀態表示是啥

其實這里借鑒了狀態壓縮二進制的思想

就是二進制拼湊

f[i][j]表示在j狀態下的當前數為i的max (我們還得知道當前數是誰是吧

爆搜咋做 ?

就是枚舉每一個后面的可以接的單詞 over?

#include <bits/stdc++.h> 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(){fastcin>>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<<ans<<endl;return ~~(0^_^0); }

691. 立方體IV

我這道題第一遍不是記憶化搜索做的

就是很簡單的找旁邊有沒有他爹

有的話標記為1

然后跑一遍連續的1?就可以了 O(1e6*100)

然后題解介紹了一種記憶化搜索的方法

我們首先想狀態?

其實直接就是f[i] i這個點可以連多長了

我們爆搜 每一個點 要是旁邊有他爹 就延續下去

這個時間復雜度是一樣的

#include <bits/stdc++.h> 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<pair<int,int>>v[M]; signed main(){fastint 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 <bits/stdc++.h> 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(){fastint 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); }

總結

以上是生活随笔為你收集整理的记忆化搜索 day48的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。