提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
蓝桥杯第十二届A组G题
提示:以下是本篇文章正文内容,下面案例可供参考
一、题目
二、思路
DP,记忆化搜索。
1.状态
d p [ i ] [ j ] dp[i][j] dp[i][j]:前 i i i个砝码能是否称量出质量为 j j j。能称量出则 d p = 1 dp=1 dp=1,否则 d p = 0 dp=0 dp=0。
2.下一个状态
从 d p [ i ] [ j ] dp[i][j] dp[i][j],可以摸一个砝码,放在左边可以转移到 d p [ i + 1 ] [ j + w [ i ] ] dp[i+1][j+w[i]] dp[i+1][j+w[i]],放在右边可以转移到 d p [ i + 1 ] [ i − w [ i ] ] dp[i+1][i-w[i]] dp[i+1][i−w[i]]。不放可以转移到 d p [ i + 1 ] [ j ] dp[i+1][j] dp[i+1][j]
3.转移方程
没啥转移方程,转过去令 d p = 1 dp=1 dp=1就好。
4.记忆化搜索
状态会被大量地重复搜索,因此判断,若当前状态已经记录过,后面的路一定被走过,就没必要再搜索了,直接 r e t u r n return return
void dfs(int num,int sum){
//cout<<"this is "<<num<<" "<<sum<<endl;
int i;
if(num==n+1)return;
if(dp[num][mabs(sum)]==0){
dp[num][mabs(sum)]=1;
}
else{//已经搜索过
return;
}
//放第num+1==i个
//左边
dfs(num+1,sum+w[num+1]);
//右边
dfs(num+1,sum-w[num+1]);
//不放
dfs(num+1,sum);
}
三、代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+7;
int w[maxn];
int vis[100007];
int fang[107];
int dp[107][100007];//dp i j 前i个砝码可以凑出j True
int n;
int cnt=0;
map<string,int>state_vis;
int mabs(int x){
if(x>0)return x;
else return -x;
}
void dfs(int num,int sum){
//cout<<"this is "<<num<<" "<<sum<<endl;
int i;
if(num==n+1)return;
if(dp[num][mabs(sum)]==0){
dp[num][mabs(sum)]=1;
}
else{
return;
}
//放第num+1==i个
//左边
dfs(num+1,sum+w[num+1]);
//右边
dfs(num+1,sum-w[num+1]);
//不放
dfs(num+1,sum);
}
void init(){
int i;
for(i=0;i<=100;i++){
for(int j=0;j<=100000;j++){
dp[i][j]=0;
}
}
}
int main(){
cin>>n;
int i;
init();
for(i=1;i<=n;i++)
{
cin>>w[i];
}
dfs(0,0);
int cnt=0;
for(i=1;i<=n;i++){
int j;
for(j=1;j<=100000;j++){
if(dp[i][j]==1){
if(vis[j]==0){
cnt++;
vis[j]=1;
}
}
}
}
cout<<cnt<<endl;
return 0;
}
总结
状态的选择很重要,选择不好会超时,代码之前要计算复杂度是否可行。