判断子集和问题是否存在解
分析思路:
采用回溯法针对问题存在解时求出相应的一个或多个解,或者最优解。如果需要判断问题是否存在解(一个或者多个),可以将求解函数改为bool型,当找到任何一个解时返回true,否则返回false,但当问题没有解时需要搜索所有空间。
法一代码:
#include<stdio.h>
#define MAXN 20
int n=4,W;
int w[]={0,11,13,24,7}; //存放所有整数解,不用下标为0的元素
bool dfs(int tw,int rw,int i) //求解子集和
{
if(i>n)
{
if(tw==W) //找到一个叶子结点
return true;
}
else //尚未找完所有物品
{
if(tw+w[i]<=W) //左孩子结点剪枝:选取满足条件的整数w[i]
return dfs(tw+w[i],rw-w[i],i+1); //选取第i个整数
if(tw+rw>W) //右孩子结点剪枝:剪除不可能存在解的结点
return dfs(tw,rw-w[i],i+1); //不选取第i个整数,回溯
}
return false;
}
bool solve() //判断子集和问题是否存在解
{
int rw=0;
for(int j=1;j<=n;j++) //求所有整数和rw
rw+=w[j];
return dfs(0,rw,1); //i从1开始
}
int main(){
W=7;
printf("W=%d时%s\n",W,(solve()?"存在解":"没有解"));
W=15;
printf("W=%d时%s\n",W,(solve()?"存在解":"没有解"));
W=21;
printf("W=%d时%s\n",W,(solve()?"存在解":"没有解"));
W=24;
printf("W=%d时%s\n",W,(solve()?"存在解":"没有解"));
}
法二:
通过解个数来判断
例:设置全局变量count表示解个数,初始化为0,调用搜索解的回溯法,当找到一个解时置count++.最后判断count>0,若为真,则表示存在解,否则表示不存在解。
法二代码:
int count; //全局变量,累计解个数
bool dfs(int tw,int rw,int i) //求解子集和
{
if(i>n)
{
if(tw==W) //找到一个叶子结点
count++;
}
else //尚未找完所有物品
{
if(tw+w[i]<=W) //左孩子结点剪枝:选取满足条件的整数w[i]
dfs(tw+w[i],rw-w[i],i+1); //选取第i个整数
if(tw+rw>W) //右孩子结点剪枝:剪除不可能存在解的结点
dfs(tw,rw-w[i],i+1); //不选取第i个整数,回溯
}
}
bool solve() //判断子集和问题是否存在解
{
count=0;
int rw=0;
for(int j=1;j<=n;j++) //求所有整数和rw
rw+=w[j];
dfs(0,rw,1); //i从1开始
if(count>0) //求所有解的情况
return true;
else
return false; //无解情况
}