洛谷(P1106)删数问题(dfs+剪枝)

题目描述
键盘输入一个高精度的正整数N(不超过250位) ,去掉其中任意k个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的N和k,寻找一种方案使得剩下的数字组成的新数最小。

输入格式:

输入两行正整数。

第一行输入一个高精度的正整数 nn。

第二行输入一个正整数 kk,表示需要删除的数字个数。

输出格式:

输出一个整数,最后剩下的最小数。
输入 

175438 
4


输出 

13

 这个题目我看网上挺多贪心解法的,我略微一看,字有点多,所以说就有一点想偷懒的感觉了,咱就说会不会这个题目还有别的比较通俗易懂的解法,你别说还真有,在这里给大家介绍一手宇宙无敌最强之dfs法,其实简单来说就是暴力破解(毕竟数据才250嘛,能暴力还要啥自行车)。思路其实很简单,你看要我删掉几个数然后找最小嘛,欧克,我把所有情况都列出来,然后找最小不就欧克了嘛,so easy。

#include"bits/stdc++.h"

using namespace std; 
const int N=300;
int vis[N];//用以标记当前节点是否走过 
int k;
string min_s,s,now_s; 
void dfs(int n,int index)//n代表当前已选数,index代表从何处开始选 
{
	if(n==k)//如果当前已经有k个数(注意k被我们弄成剩余个数了,不要傻傻认为还是要删掉的数) 
	{
		if(now_s>s;
	cin>>k;
	min_s+=('9'+1);//初始化max_s比9就行毕竟是字符串比较 
	k=s.length()-k;//要删掉k个数等于要留s.length()-k个 
	dfs(0,0);
	int index=0;
	while(min_s[index]=='0')	index++;//去除前导0 
	for(int i=index;i

就这么简单嘛,暴力破解随便拿捏。然后当你美滋滋的提交时,结果是熟悉的老朋友TLE。究其原因嘛,还是暴力破解的解题效率不行,它可以解决大部分题目,却不能让它们都在规定时间完成。这就可以让我放弃暴力吗这是不可能滴,我们还有后手,给它修饰一下。如果说当前now_s已经比min_s大了,我们还有必要往它后面加数然后比较吗?显然是不用的,因此我们如果发现已经没有必要比的时候就可以跳出循环了,然后就可以得到以下代码了。

#include"bits/stdc++.h"

using namespace std; 
const int N=300;
int vis[N];//用以标记当前节点是否走过 
int k;
string min_s,s,now_s; 
void dfs(int n,int index)//n代表当前已选数,index代表从何处开始选 
{
	if(n==k)//如果当前已经有k个数(注意k被我们弄成剩余个数了,不要傻傻认为还是要删掉的数) 
	{
		if(now_smin_s)
			break;//剪枝 
		if(vis[i]==0)
		{
			string front_s=now_s;//注意要记录前面的now_s因为dfs过后要回溯 
			now_s+=s[i]; 
			vis[i]=1;
			dfs(n+1,i+1);//当前点可选则选入然后进入下一个dfs 
			now_s=front_s;
			vis[i]=0;//回溯 
		}
	}
}
int main()
{
	cin>>s;
	cin>>k;
	min_s+=('9'+1);//初始化max_s比9大1就行毕竟是字符串比较 
	k=s.length()-k;//要删掉k个数等于要留s.length()-k个 
	dfs(0,0);
	int index=0;
	while(min_s[index]=='0')	index++;//去除前导0 
	for(int i=index;i

然后就可以成功ac了,这里我有一个问题,front_s如果放在全局变量就不能过全部测试点,但放在循环string front_s;就可以ac,这里我搞不懂,希望有高手给我解惑。

你可能感兴趣的:(c++,深度优先,剪枝,算法)