棋盘DP

主要是在棋盘上的DP,棋盘上每个点的转移状态基本上都是已知的

复制代码
//https://www.luogu.com.cn/problem/P1896 //压状dp //由于时间复杂度达到了指数级复杂度,所以搜索不能进行 //考虑动态规划,dp i,j,k表示 第i行,使用了j个国王,此时的状态是k // 对于第i行,若要求此时符合条件,有: 第i行中的棋子,两两互不相邻,即check(a|b)=true // 对于第i-1行,有与第i行的国王不相邻,所以使用&运算即可 #include<bits/stdc++.h> using namespace std; const int N=12,M=1<<10,K=110; int n,m,cnt[M],dp[N][M][K]; vector<int>state,head[M];//把状态存入state中 int count(int x)//计算1的个数 { int res=0; for(int i=0;i<n;i++) if((x>>i&1)==1) res++; return res; } bool check(int x) //检查相邻两位是否连续为1 { for(int i=0;i<n;i++) if((x>>i&1)&&(x>>i+1&1)) return false; return true; } int main() { cin>>n>>m; for(int i=0;i<1<<n;i++) if(check(i)) state.push_back(i),cnt[i]=count(i); for(int i=0;i<state.size();i++) for(int j=0;j<state.size();j++){ int a=state[i],b=state[j]; if(!(a&b)&&check(a|b)) head[i].push_back(j); } dp[0][0][0]=1; for(int i=1;i<=n+1;i++) for(int j=0;j<=m;j++) for(int a=0;a<state.size();a++) for(int b:head[a]){ int c=cnt[state[a]]; if(j>=c) dp[i][j][a]+=dp[i-1][j-c][b]; } cout<<dp[n+1][m][0]; return 0; }
复制代码

 

复制代码
//https://www.luogu.com.cn/problem/P1004 //首先提供二维dp,二维dp的思路为ij表示i行j列时的可以取得最大值 //类似于贪心,先进行第一遍循环,取到最优,然后把第一遍取的数全变为0,再进行第二遍的取 //但是这种方法并不一定是全局的最优解 //0 0 2 3 0 0 0 //0 0 3 0 0 0 0 //0 0 3 0 0 0 0 //0 0 0 0 0 0 0 //0 0 0 0 4 0 0 //0 0 0 0 4 0 0 //0 0 0 0 4 0 0 //如图,走第一遍可得出终点时最大值为20,去掉已经走过的点后图如下: //0 0 0 3 0 0 0 //0 0 0 0 0 0 0 //0 0 0 0 0 0 0 //0 0 0 0 0 0 0 //0 0 0 0 0 0 0 //0 0 0 0 0 0 0 //0 0 2 0 0 0 0 //然后会发现我们无法全部走完,也正符合贪心策略,“只注重眼前的利益”,因此此题使用二维dp绝非正解,上代码: #include<bits/stdc++.h> using namespace std; const int N=10; int dx[]={0,1},dy[]={1,0},n,mp[N][N]; int dp[N][N],res,ans; int main() { cin>>n; int a,b,c; while(cin>>a>>b>>c&&a+b+c>0) mp[a][b]=c; // for(int i=1;i<=n;i++){ // for(int j=1;j<=n;j++) cout<<mp[i][j]<<' '; // cout<<endl; // } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dp[i][j]=max(dp[i-1][j]+mp[i][j],dp[i][j-1]+mp[i][j]); res=dp[n][n],ans=dp[n][n]; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(dp[i][j]==res&&dp[i][j]!=0) res-=mp[i][j],mp[i][j]=0,i=0,j=0; } } memset(dp,0,sizeof dp); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dp[i][j]=max(dp[i-1][j]+mp[i][j],dp[i][j-1]+mp[i][j]); cout<<ans+dp[n][n]; return 0; } //正确思路: //四维dp,用ijkl表示思维,ij表示第一遍走的,kl表示第二遍走的,然后进行n^4的dp //如果遇到相同的点就直接减去 #include<bits/stdc++.h> using namespace std; const int N=10; int n,m,dp[N][N][N][N],mp[N][N]; int main() { cin>>n; int a,b,c; while(cin>>a>>b>>c&&a+b+c>0) mp[a][b]=c; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) for(int l=1;l<=n;l++){ dp[i][j][k][l]=max(max(dp[i-1][j][k-1][l],max(dp[i-1][j][k][l-1],dp[i][j-1][k][l-1])),dp[i][j-1][k-1][l])+mp[i][j]+mp[k][l]; if(i==k&&j==l) dp[i][j][k][l]-=mp[k][l]; } cout<<dp[n][n][n][n]; return 0; }
复制代码

 


__EOF__

本文作者Sakurajimamai
本文链接https://www.cnblogs.com/o-Sakurajimamai-o/p/17831019.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   o-Sakurajimamai-o  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
-- --
点击右上角即可分享
微信分享提示