dfs问题小结 及基本问题解决
根据现已做的题目 大多数的dfs题都可以用下面的模板解决
dfs( 一系列的变化的量)
{
if(判断递归的退出条件 可能用多个if来表示多个情况)
{
//加上一系列的操作 在符合退出条件下
return;
}
dfs(变化后的新变量)
//这里回溯退出,就是在dfs退出之后的执行的操作
}
第一题
pat 1103 利用dfs解题 大意:题目给出正整数N、个数K和次数P,要求将正整数N分解为K个正整数P次方的和,并按照题目要求输出。
题目
代码如下
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
int n,k,p,maxfacsum=-1;
vector <int> fac,ans,temp;
int power(int x)
{
int ans=1;
for(int i=0;i<p;i++)
{
ans*=x;//求x的p次
}
return ans;
}
void init()
{
int i=0,temp=0;
while(temp<=n)
{
fac.push_back(temp);
temp=power(++i);
}
}
void dfs(int index, int nowk, int sum, int facsum)
{
if(sum==k && nowk==k)
{
if(facsum >maxfacsum)
{
ans=temp;
maxfacsum=facsum;
}
return;
}
if(sum>n || nowk>k) return ;//这种情况无答案 直接返回
if(index-1 >=0)//fac[0]不用选择
{
temp.push_back(index);
dfs(index , nowk+1,sum+fac[index], facsum+index);
temp.pop_back();//选的分支结束后 把刚加的数pop
dfs(index-1,nowk,sum,facsum);
}
}
int main()
{
scanf("%d%d%d",&n,&k,&p);
init();
dfs(fac.size()-1,0,0,0);//从fac的最后一位开始往前搜索
if(maxfacsum ==-1)
printf("Impossible\n");
else
{
printf("%d=%d^%d",n,ans[0],p);
for(int i=1;i<ans.size();i++)
{
printf(" + %d^%d",ans[i],p);
}
}
system("pause");
return 0;
}
第二题
PAT A1079
根节点为·供应商 叶子结点为销售商 过一层涨幅为r% 求他们的价格之和
利用dfs解题 变化的量是depth 注意这里的dfs要对酶一个结点进行 所以用了for循环语句 for(int i=0;i<Node[index].child.size(); i++)
初始的时候 depth为0 因为第一层不加r%
代码如下
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
const int maxn=100010;
struct node{
double data;//货量
vector<int> child;//节点数
}Node[maxn];
int n;
double p,r,ans=0;
void dfs(int index,int depth)
{
if(Node[index].child.size() == 0)
{
ans+=Node[index].data * pow(1+r,depth);
return;
}
for(int i=0;i<Node[index].child.size(); i++)
{
dfs(Node[index].child[i],depth+1);
}
}
int main()
{
int k,child;
cin>>n>>p>>r;
//scanf("%d%lf%lf",&n,&p,&r);
r=r/100;
for(int i=0;i<n;i++)
{
cin>>k;
//scanf("%d",&k);
if(k==0)
{
cin>>Node[i].data;
//scanf("%lf",&Node[i].data);
}
else
{
for(int j=0;j<k;j++)
{
cin>>child;
//scanf("%d",&child);
Node[i].child.push_back(child);
}
}
}
dfs(0,0);
printf("%.1f\n",p*ans);
system("pause");
return 0;
}
第三题
pat A 1090
题目同上 求的是价格最高的叶子结点 以及最高价格的叶子结点数量
代码如下 注意体会递归出口条件之间的区别· pow函数的功能是实现幂次的计算
#include <iostream>
#include<cstdio>
#include <vector>
#include <cmath>
using namespace std;
const int maxn=100010;
vector<int> child[maxn];
int n;
double p,r;
int num=0,maxdepth=0;
void dfs(int index,int depth)
{
if(child[index].size()== 0)
{
if(depth>maxdepth)
{
maxdepth=depth;
num=1;
}
else if(depth == maxdepth)
{num++;}
return;
}
for(int i=0;i<child[index].size();i++)
{
dfs(child[index][i],depth+1);
}
}
int main()
{
int father,root;
scanf("%d%lf%lf",&n,&p,&r);
r=r/100;
for(int i=0;i<n;++i)
{
scanf("%d",&father);
if(father !=-1)
{
child[father].push_back(i);
}
else{
root=i;
}
}
dfs(root,0);
double ans=p*pow(1+r,maxdepth);
printf("%.2f %d\n",ans,num);
system("pause");
return 0;
}
第四题
Pat
啊1106
接下来求的是 最便宜的叶子结点 及其个数
代码如下
#include <iostream>
#include <cstdio>
#include <vector>
#include<cmath>
using namespace std;
const int maxn=100010;
const int inf=1e12;//10的12次
vector <int>Node[maxn];
int n,num=0;
double p,r,ans=inf;
void dfs(int index,int depth)
{
if(Node[index].size()==0)
{
double price=p*pow(1+r,depth);
if(price<ans)
{
ans=price;
num=1;
}
return ;
}
for(int i=0;i<Node[index].size();++i)
{
dfs(Node[index][i],depth+1);
}
}
int main()
{
int k,child;
scanf("%d%lf%lf",&n,&p,&r);
r=r/100;
for(int i=0;i<n;++i)
{
scanf("%d",&k);
if(k!=0)
{
for(int j=0;j<k;++j)
{
scanf("%d",&child);
Node[i].push_back(child);
}
}
}
dfs(0,0);
printf("%.4f %d\n",ans,num);
system("pause");
return 0;
}
第五题
Pat A 1053
输出从根节点到叶子结点的路劲为s的所有路劲 如果有多条 按路劲非递增输出 注意多了一个path来存储路劲
代码如下
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 110;
struct node{
int weight;
vector <int> child;
}Node[maxn];
bool cmp(int a,int b)
{
return Node[a].weight > Node[b].weight;//按节点大小从大到小排序
}
int m,n,s;
int path[maxn];
void dfs(int index, int numnode ,int sum)//index 当前访问节点 nodesum路径中节点个数 sum就是路劲和
{
if(sum>s) return;
if(sum == s)
{
if(Node[index].child.size() != 0) return;//没到叶子节点 回退
//到了叶子节点 输出路劲
for(int i=0;i<numnode;++i)
{
printf("%d",Node[path[i]].weight);
if(i<numnode -1)
printf(" ");
else printf("\n");
}
return;
}
for(int i=0;i<Node[index].child.size();++i)
{
int child = Node[index].child[i];
path[numnode] = child;
dfs(child,numnode+1,sum+Node[child].weight);
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=0;i<n;++i)
{
scanf("%d",&Node[i].weight);
}
int id,k,child;
for(int i=0;i<m;++i)
{
scanf("%d%d",&id,&k);
for(int j=0;j<k;++j)
{
scanf("%d",&child);
Node[id].child.push_back(child);
}
sort(Node[i].child.begin(), Node[i].child.end(),cmp);
}
path[0]=0;
dfs(0,1,Node[0].weight);
system("pause");
return 0;
}