一、介绍
设计一个整型可变参数status,利用status的位信息,来表示某个样本是否还能使用,然后利用这个信息进行尝试。
dfs+记忆化
二、习题
1.can I win?
class Solution {
public:
int memo[1<<21];//记忆数组
bool canIWin(int maxChoosableInteger, int desiredTotal) {
if((1+maxChoosableInteger)*(maxChoosableInteger)/2<desiredTotal)return false;
if(desiredTotal==0)return true;
return dfs(maxChoosableInteger,0,desiredTotal);
}
bool dfs(int maxChoosableInteger,int status,int res){
if(memo[status])return memo[status]==1?true:false;
for(int i=1;i<=maxChoosableInteger;i++){
if(status&(1<<i))continue;
if(res-i<=0){
memo[status]=1;
return true;
}
if(!dfs(maxChoosableInteger,status^(1<<i),res-i)){
memo[status]=1;
return true;
}
}
memo[status]=2;
return false;
}
};
2.火柴拼正方形
class Solution {
public:
int mem[1<<16];
bool makesquare(vector<int>& matchsticks) {
int sum=0,n=matchsticks.size();
for(int i=0;i<n;i++){
sum+=matchsticks[i];
}
if(sum%4)return false;
return f(matchsticks,sum/4,0,(1<<n)-1,4);
}
bool f(vector<int>&matchsticks,int limit,int cur,int state,int res){
if(res==0)return state==0;
if(mem[state])return mem[state]==1;
bool ans=false;
for(int i=0;i<matchsticks.size();i++){
if((state&(1<<i))==0)continue;
if(cur+matchsticks[i]>limit)continue;
if((cur+matchsticks[i])==limit){
ans=f(matchsticks,limit,0,state ^ (1<<i),res-1);
}else{
ans=f(matchsticks,limit,cur+matchsticks[i],state ^ (1<<i),res);
}
if(ans){
break;
}
}
mem[state]=ans?1:-1;
return ans;
}
};
3.售货员的难题
题目背景
数据有更改
题目描述
某乡有 n ( 2 ≤ n ≤ 20 ) n\ (2\le n\le 20) n (2≤n≤20) 个村庄,有一个售货员,他要到各个村庄去售货,各村庄之间的路程 s ( 0 < s < 1000 ) s\ (0<s<1000) s (0<s<1000) 是已知的,且 A A A 村到 B B B 村与 B B B 村到 A A A 村的路大多不同。为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为 1 1 1,他不知道选择什么样的路线才能使所走的路程最短。请你帮他选择一条最短的路。
输入格式
村庄数 n n n 和各村之间的路程(均是整数)。
第一行,第 i + 1 i+1 i+1 行第 j j j 个数代表村庄 i i i 到 j j j 的单向路径的路程。
输出格式
最短的路程。
样例 #1
样例输入 #1
3
0 2 1
1 0 2
2 1 0
样例输出 #1
3
dfs+记忆化
#include<bits/stdc++.h>
using namespace std;
#define N 30
int dis[N][N];
int n;
int mem[N][1<<21];
int dfs(int status,int now){
int ans=1e9;
if(status==((1<<n)-1))return dis[now][0];
if(mem[now][status])return mem[now][status];
for(int i=1;i<n;i++){
if(status&(1<<i))continue;
ans=min(ans,dfs(status^(1<<i),i)+dis[now][i]);
}
mem[now][status]=ans;
return ans;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&dis[i][j]);
}
}
int ans=dfs(1,0);
printf("%d",ans);
return 0;
}
dp法
#include<bits/stdc++.h>
using namespace std;
#define N 30
int dis[N][N];
int n;
int dp[1<<20][20];
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&dis[i][j]);
}
}
memset(dp,0x3f,sizeof dp);
dp[1][0]=0;
for(int i=1;i<(1<<n);i+=2){
for(int j=1;j<n;j++){
if(!(i>>j)&1)continue;
for(int k=0;k<n;k++){
if(k==j)continue;
if(!(i>>k)&1)continue;
dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+dis[k][j]);
}
}
}
int ans=INT_MAX;
for(int i=1;i<n;i++){
ans=min(ans,dp[(1<<n)-1][i]+dis[i][0]);
}
printf("%d",ans);
return 0;
}
总结
状压dp先这样吧,先入个门,难题之后在搞