深度优先搜索

P2089 烤鸡

可选可不选问题模型

循环嵌套暴力

#include <bits/stdc++.h>
using namespace std;
int n, a[10], count=0, sum=0;
int main()
{
	cin >> n;	
	if(n>30 || n<10)
		cout << "0";
	else
	{
		for(a[0]=1; a[0]<=3; a[0]++)	
		{
			for(a[1]=1; a[1]<=3; a[1]++)
			{
				for(a[2]=1; a[2]<=3; a[2]++)
				{
					for(a[3]=1; a[3]<=3; a[3]++)
					{
						for(a[4]=1; a[4]<=3; a[4]++)
						{
							for(a[5]=1; a[5]<=3; a[5]++)
							{
								for(a[6]=1; a[6]<=3; a[6]++)
								{
									for(a[7]=1; a[7]<=3; a[7]++)
									{
										for(a[8]=1; a[8]<=3; a[8]++)
										{
											for(a[9]=1; a[9]<=3; a[9]++)
											{
												for(int i=0; i<10; ++i)
												{
													sum+=a[i];
												}
												if(sum==n)
												{
													count++; 
												}
												sum=0;
											}
										}
									}
								}
							}
						}
					}
				}	
			}	
		}
		
		cout << count << endl;
		
		for(a[0]=1; a[0]<=3; a[0]++)	
		{
			for(a[1]=1; a[1]<=3; a[1]++)
			{
				for(a[2]=1; a[2]<=3; a[2]++)
				{
					for(a[3]=1; a[3]<=3; a[3]++)
					{
						for(a[4]=1; a[4]<=3; a[4]++)
						{
							for(a[5]=1; a[5]<=3; a[5]++)
							{
								for(a[6]=1; a[6]<=3; a[6]++)
								{
									for(a[7]=1; a[7]<=3; a[7]++)
									{
										for(a[8]=1; a[8]<=3; a[8]++)
										{
											for(a[9]=1; a[9]<=3; a[9]++)
											{
												for(int i=0; i<10; ++i)
												{
													sum+=a[i];
												}
												if(sum==n)
												{
													for(int i=0; i<10; ++i)
													{
														cout << a[i] << " ";
													}
													cout << endl;	
												}
												sum=0;
											}
										}
									}
								}
							}
						}
					}
				}	
			}	
		}		
	}	
	return 0;
}

搜索

#include <bits/stdc++.h>
using namespace std;
int n, a[10], total=0, b[100000][10];
void dfs(int t, int sum)
{
	//如果配料总和已经大于给定的n,那么当前这一枝方案不合理 
	if(sum>n)	return;
	else if(t==11&&sum!=n)	return;  //全部配完,扔达不到n,当前方案也不合理 
	else if(t==11 && sum==n)         //10种配料全部配完,并且总数为n 
	{
		//将配料方案记录下来,因为需要先输出总方案数 
		for(int i=0; i<10; i++)
		{
			b[total][i]=a[i];
		}
		//方案数加一 
		total++;                       
		return;
	}
	
	for(int i=1; i<=3; i++)
	{
		a[t-1]=i;
		dfs(t+1, sum+i);
	}
} 

int main() 
{
	cin >> n;
	if(n<10 || n>30)
	{
		cout << "0";
		return 0;	
	}
	else dfs(1, 0); //从第一种配料开始搜索,初始配料总和为0. 
	cout << total << endl;
	for(int i =0; i<total; i++)
	{
		for(int j=0; j<10; j++)
		{
			cout << b[i][j] << " ";
		}
		cout << endl;
	}
    return 0;
}

P1460 [USACO2.1]健康的荷斯坦奶牛 Healthy Holsteins

可选可不选问题模型

#include <bits/stdc++.h>
using namespace std;
int v, g, need[30], a[20][30], c[20], s[30], ans=20, asd[20];
//准备看第cnt种饲料用还是不用, 当前用了num种饲料, 
//这num种饲料的编号存在cur数组中, 第i种维他命的量为sum[i] 
void dfs(int cnt, int num, int cur[20], int sum[30])
{
	int ok=0;
	//可行性剪枝, 已经超了 
	if(cnt>g+1){
		return;
	}
	//前cnt-1种饲料,够不够 
	for(int i=1; i<=v; ++i){
		if(sum[i]>=need[i]){
			ok++;
		}
		else{
			break;
		}
	} 
	//最优性剪枝 
	if(ok==v){
		if(num<ans){
			ans=num;
			for(int i=1; i<=num; ++i){
				asd[i]=cur[i];
			}
		}
		return;
	}
	int cur2[20], sum2[30];
	for(int i=1; i<=num; ++i){
		cur2[i]=cur[i];
	}
	for(int i=1; i<=v; ++i){
		sum2[i]=sum[i];
	}
	cur2[num+1]=cnt; 
	for(int i=1; i<=v; ++i){
		sum2[i]+=a[cnt][i];
	}
	dfs(cnt+1, num+1, cur2, sum2);	//先选, 可以保证字典序最小 
	dfs(cnt+1, num, cur, sum);		//不选第cnt种饲料	
}
int main()
{
	scanf("%d", &v);	//表示需要的维他命的种类数
	for(int i=1; i<=v; ++i){
		scanf("%d", &need[i]);	//每天需要的每种维他命的最小量
	}	
	scanf("%d", &g);	//可用来喂牛的饲料的种数
	for(int i=1; i<=g; ++i){
		for(int j=1; j<=v; ++j){
			scanf("%d", &a[i][j]);	//第i种饲料包含的第j种维他命的量
		}
	}
	dfs(1, 0, c, s);	//准备看第1种饲料选还是不选, 当前选了0种饲料,  
	printf("%d ", ans);
	for(int i=1; i<=ans; ++i){
		printf("%d ", asd[i]);
	} 
	return 0;
}

测试数据2

.in

25
826 953 853 512 620 769 722 833 719 754 730 521 908 622 877 737 534 882 560 812 684 787 984 983 783
15
167 78 129 9 41 56 71 132 29 45 61 152 13 76 172 152 27 21 0 38 24 93 25 155 18
84 69 79 59 179 166 107 28 79 63 11 101 95 73 172 70 141 97 72 170 74 132 48 195 136
88 97 174 121 28 28 157 29 56 148 1 46 160 188 114 179 49 55 22 20 79 98 144 153 100
98 23 58 152 58 197 72 199 1 171 18 57 61 64 78 100 61 192 135 92 80 168 129 144 192
178 80 119 78 95 14 15 102 26 135 127 145 130 95 117 193 95 98 19 163 135 81 74 182 85
121 35 187 43 113 58 56 152 56 183 162 76 90 43 138 38 142 107 156 197 105 81 95 29 9
182 124 77 118 106 55 143 6 18 194 92 145 159 61 132 59 12 80 144 179 39 42 122 51 102
14 107 32 188 114 67 127 165 15 100 102 183 5 34 125 28 69 180 69 71 2 114 131 107 45
64 107 118 27 151 160 74 129 77 35 188 35 105 160 148 189 122 177 144 139 33 145 5 59 74
162 74 58 98 48 123 149 6 35 148 93 2 103 144 189 28 108 91 26 49 150 64 81 166 119
87 144 20 64 49 93 51 132 105 185 91 115 74 169 46 154 55 17 159 42 188 163 189 73 161
36 7 65 4 4 162 132 166 89 82 10 13 182 92 118 157 123 106 168 127 158 169 84 21 159
112 73 38 102 93 185 119 195 97 10 14 156 146 54 190 26 111 44 109 18 83 91 78 193 164
175 7 54 63 78 84 60 156 20 84 140 183 130 142 14 41 17 97 14 60 155 27 184 9 156
103 173 20 51 174 96 90 35 196 77 122 23 137 43 195 41 70 89 4 26 64 186 170 51 13

.out

10 2 3 5 6 7 8 9 11 13 15

P1706 全排列问题

可选可不选问题模型,选过的不能再选

#include <bits/stdc++.h>
using namespace std;
int n, sum, a[11];
bool vis[11]; 
//准备给第cnt个位置放数字 
void dfs(int cnt)
{
	if(cnt>n){	//前n个位置都安排好数字了 
		for(int i=1; i<=n; ++i){
			printf("%5d", a[i]);
		}
		printf("\n");
		return;
	}
	//枚举第cnt个位置上所有的可能性 
	for(int i=1; i<=n; ++i){
		if(!vis[i]){	//如果i这个数还没被安排 
			a[cnt]=i;	//放在第cnt个位置上 
			vis[i]=1;	//标记 
			dfs(cnt+1);	//继续安排下一个 
			vis[i]=0;	//回溯 
		}
	} 
}

int main()
{
	scanf("%d", &n);
	dfs(1);
	return 0;
}

P1157 组合的输出

可选可不选问题模型,选过的不能再选,后面选的要大于前面选的

#include <iostream>
using namespace std;
int n, r;
int a[21];
void dfs(int cnt)
{
	if(cnt==r+1){
		for(int i=1; i<=r; i++)
			printf("%3d", a[i]);
		printf("\n");
		return;
	}
	for(int i=a[cnt-1]+1; i<=n-r+cnt; i++){
		a[cnt]=i;	 
		dfs(cnt+1);
	}
}
int main()
{
	cin >> n >> r;
	dfs(1);
	return 0;
}

P1036 [NOIP2002 普及组] 选数

#include <iostream>
#include <math.h>
using namespace std;
int n, k, ans, a[21];

//判断是否为质数 
bool isprime(int num)
{
	//1不是质数 
	if(num<2){
		return false;
	}
	for(int i=2; i<=sqrt(num); ++i){
		if(num%i==0){
			return false;
		}
	}
	return true;
}
//cnt表示找a[]数组中第几个数,flag表示准备选第几个数, sum表示当前的和 
void dfs(int cnt, int flag, int sum)
{
	//搜索/递归的边界结束条件:如果k个数已经选好了 
	if(flag==k+1 && cnt<=n+1){
		//判断这一决策分支和是否为质数 
		if(isprime(sum)){
//			cout << sum << endl;
			ans++;
		}
		//k个数已经选好了,说明已经到达决策树叶子节点,
		//所以不管和是不是质数,都要结束当前分支的搜索 
		return;
	}
	else{
		//可以选数,从数组中的第cnt个开始选,为第flag个数做选择。
		for(int i=cnt; i<=n; ++i){
			//每一个循环是一个独立的分支,不需要代码实现回溯 
			dfs(i+1,flag+1,sum+a[i]);
		}
	}
} 
int main()
{
	//n个数里选k个,求和,并判断和是否为质数 
	cin >> n >> k;
	//输入这n个数 
	for(int i=1; i<=n; ++i){
		cin >> a[i];
	}
	//开始从数组中第一个数选
	dfs(1,1,0);
	cout << ans;
	
	return 0;
}

P3956 [NOIP2017 普及组] 棋盘

#include <bits/stdc++.h>
using namespace std;
int n, m, color[110][110], ans, dis[110][110];
int mx[5]={0, -1, 1, 0, 0};
int my[5]={0, 0, 0, -1, 1};
bool vis[110][110], asd[110][110];		//asd表示原始是否有颜色 
//当前在第x行, y列, 当前的最少步数为cur 
void dfs(int x, int y, int cur)
{
	//递归出口 
	if(x==m && y==m){	
		if(cur<dis[m][m]){
			dis[m][m]=cur;
		} 
		return;
	} 
	//剪枝 
	if(cur>=dis[x][y]){
		return;
	}
	else{
		dis[x][y]=cur;		//保持当前最右 
		vis[x][y]=true;		//标记 
		for(int i=1; i<=4; ++i){	//枚举上下左右 
			int nx=x+mx[i];
			int ny=y+my[i];
			//没出界, 没走过 
			if(nx>=1 && nx<=m && ny>=1 && ny<=m && !vis[nx][ny]){
				//都有颜色, 并且颜色相同, 不需要花费金币,  
				if(asd[x][y] && asd[nx][ny] && color[x][y]==color[nx][ny]){	
					
					dfs(nx, ny, cur);
				}
				else if(asd[x][y] && asd[nx][ny] && color[x][y]!=color[nx][ny]){	
					dfs(nx, ny, cur+1);		//都有颜色, 并且颜色不同, 需要花费1个金币 
				}
				else if(!asd[x][y] && asd[nx][ny]){
					//x,y没有颜色, nx, ny有颜色 
					if(color[x][y]==color[nx][ny]){		//颜色相同, 不需要花费金币 
						dfs(nx, ny, cur);
					}
					else{					//颜色不同, 花费1个金币 
						dfs(nx, ny, cur+1);
					} 
				}
				else if(asd[x][y] && !asd[nx][ny]){
					//x,y有颜色, nx, ny没有颜色, 给nx, ny染为相同色 
					color[nx][ny]=color[x][y];
					dfs(nx, ny, cur+2);		//染色需要花费2个金币
//					color[nx][ny]=0;		//这块不需要回溯 
				} 
			}
		}
		vis[x][y]=false;	//回溯 
	}
}
int main()
{
	freopen("P3956_3.in", "r", stdin);
	int x, y, c;
	scanf("%d %d", &m, &n);
	while(n--){
		scanf("%d %d %d", &x, &y, &c);
		color[x][y]=c;
		asd[x][y]=true;	//最开始有颜色 
	}
	memset(dis, 0x7f, sizeof(dis));		//初始化为一个比较大的值 
	dfs(1, 1, 0);
	if(dis[m][m]==0x7f7f7f7f){
		puts("-1");
	}
	else{
		cout << dis[m][m];	
	}
	return 0;
}

提供一个数据点

.in

3 5
1 1 0
1 3 1
2 2 1
2 3 0
3 1 1

.out

6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ypeijasd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值