深度优先搜索(DFS)
让我们从刷题开始,掌握DFS
1. POJ-1258 Sum It Up
题面
给定指定的t和n个整数的列表,使用列表中加起来为t的数字查找所有不同的总和。例如,如果t = 4,n = 6,列表是[4,3,2,2,1,1],那么有四个不同的总和等于4:4,3 + 1,2 + 2,和2 + 1 + 1。(一个数字可以在一个总和中使用,就像它在列表中出现的次数一样,一个数字算作一个总和。)你的工作就是解决这个问题。
输入
输入将包含一个或多个测试用例,每行一个。每个测试用例包含t,total,后跟n,列表中的整数数,后跟n个整数x1,…,xn。如果n = 0,则表示输入结束;否则,t将是小于1000的正整数,n将是1到12之间的整数(包括),x1,…,xn将是小于100的正整数。所有数字将被恰好一个空格分隔。每个列表中的数字以非递增顺序显示,并且可能存在重复。
输出
对于每个测试用例,首先输出一行包含’Sums of’,total和冒号。然后输出每个总和,每行一个;如果没有总和,则输出’NONE’行。每笔金额中的数字必须以非递增顺序出现。数字可以在原始列表中重复多次重复。总和本身必须根据总和中出现的数字按递减顺序排序。换句话说,总和必须按其第一个数字排序;具有相同第一个数字的总和必须按其第二个数字排序;前两个数字相同的总和必须按第三个数字排序;等等。在每个测试用例中,所有总和必须是不相干的;相同的总和出现两次。
样本输入
4 6 4 3 2 2 1 1
5 3 2 1 1
400 12 50 50 50 50 50 50 25 25 25 25 25 25
0 0
样本输出
总和4:
4
3 + 1
2 + 2
2 + 1 + 1
总和5:
没有
总和400:
50 + 50 + 50 + 50 + 50 + 50 + 25 + 25 + 25 + 25
50 + 50 + 50 + 50 + 50 + 25 + 25 + 25 + 25 + 25 + 25
我觉得最重要的就是明白
1.题目考什么,分析思路
2.代码怎么写出来的
3.了解DFS过程
写代码过程
1.这道题就是考 DFS+去重
明白DFS和去重的代码思想
DFS过程
int s[15] //存储每次搜索过程中的数,称它为 结果数组吧
int a[15] //main函数中输入的数组
void dfs(int step,int sum, int d) //step 结果数组下标,sum 数组和 ,d 输入的数组下标
{
//判断边界
if(){
//当到达边界时的操作;
}
for(int i= ,i< ;i++){ //尝试每一种可能
dfs(step+1,sum+a[i],i+1); //进行下一步
……… //去重;
}
}
主要理解一下去重
while(i+1<n&&a[i]==a[i+1])
i++;
i+1<n :判断i不过界
a[i]==a[i+1] :当从a[i]开始时,a[i]为第一位的所有情况已经找出,
因为经过sort排序,相同的数会排在一起,后面再出现相同的数为第一位,
会有相同的结果出现。所以要把跳过相同的数。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
int t,n,total;
int s[15];
int book[15];
int a[15];
int c;
void dfs(int step,int sum,int d)
{
if(sum>t||step==n)return;
if(sum==t) //判断边界
{
for(int j=0;j<step;j++)
{
cout<<sss[j];
if(j!=step-1)cout<<"+";
}
cout<<endl;
c=1;
return;
}
for(int i=d;i<n;i++)
{
sss[step]=a[i];
dfs(step+1,sum+a[i],i+1);
while(i+1<n&&a[i]==a[i+1])
i++;
}
}
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
cin>>t>>n;
while(t!=0&&n!=0){
for(int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n,cmp);
cout<<"Sums of "<<t<<":"<<endl;
c=0;
dfs(0,0,0);
if(!c)cout<<"NONE"<<endl;
cin>>t>>n;
}
return 0;
}