【回溯法】NJU201802

1.题目

Missing number

Given a positive integer n(n≤40), pick n-1 numbers randomly from 1 to n and concatenate them in random order as a string s, which means there is a missing number between 1 and n. Can you find the missing number?(Notice that in some cases the answer will not be unique, and in these cases you only need to find one valid answer.

【例】

  Input: 20
         81971112205101569183132414117
  Output: 16

2. 思路分析

  • 参考链接link给出的提示,该题仍可采用回溯法
  • 但特别之处在于需要对字符串进行分割,对每个数字可能有两种分法,要么本身,要么和后一个组合在一起(n<40),相当于回溯法的两个分支。优先考虑和后面一个数字组合,并判断当前组合数字是否小于n,且是否被访问过。
  • 另外一个坑点是,base case的判断不是Index指向N-1,而是字符串的最后一位(为此debug了好久)。总之,字符串分割细节很多,需要注意。

3. 源码

/*Given a positive integer n(n≤40), 
pick n-1 numbers randomly from 1 to n and concatenate them in random order as a string s,
which means there is a missing number between 1 and n. 
Can you find the missing number?
(Notice that in some cases the answer will not be unique, 
and in these cases you only need to find one valid answer.)

给一个由N-1个数字拼成的字符串,找缺失的一个数字
【例】  
Input: 20
   81971112205101569183132414117
Output: 16
分割为7 19 7 11 12 20 5 10 15 6 9 18 3 13 2 4 14 1 17

Input: 9
  12345679
Output: 8


*/
#include <iostream>
#include<string>
#include<vector>
#include<cstring>
using namespace std;

//判断对应数字是否被访问,从1开始的
bool visit[51];
int ans;
string input="";
vector<int> keep;

bool backtrace(int index, int n)
{
    //basecase 
    if (index == input.size())
    {
        int num = 0;
        int unvis = 0;
        for (int j = 1; j <= n; j++)
        {
            if (visit[j] == true)
                num++;
            else if (visit[j] == false)
            {
                cout << unvis << "未访问" << endl;
                unvis = j;
            }
               // unvis = j;
        }
        if (num == n - 1)
        {
            ans = unvis;
          
            return true;
        }
        else 
        {
            return false;
        }
    }//basecase

    if( (n >= 10)&&(index<=input.size()-2))
    {
        if (input[index] != '0')
        {
            //cout << input[index] << "ttttt" << endl;
            //cout << input[index + 1] << "rrrrrr" << endl;
            int bignum = 10 * (input[index] - '0') + (input[index + 1] - '0');
          //  cout << bignum << "pppp" << endl;

            if ((visit[bignum] == false) && (bignum <= n))
            {
                visit[bignum] = true;
                keep.push_back(bignum);
                //cout << bignum << "大数索引" << endl;
               
                if (backtrace(index + 2, n))
                {
                    
                    return true;
                }
                  
                else
                {
                    visit[bignum] = false;
                    keep.pop_back();
                }

            }
           
            
       }
           
    }

    //string test1 = "";
  //  test1=test1+input[index];
    //int smallnum = stoi(test1);
    
    int smallnum = input[index] - '0';
    //cout << smallnum << "小数" << endl;
    //cout << index << "小数索引" << endl;
    if (smallnum != 0)
    {
        //cout << smallnum << "kk" << endl;
        if ((visit[smallnum] == false)&&(smallnum<=n))
        {
            visit[smallnum] = true;
            keep.push_back(smallnum);
            //cout << smallnum << "?????" << endl;
            if (backtrace(index + 1, n))
                return true;
            else
            {
                visit[smallnum] = false;
                keep.pop_back();
            }
        }
     

    }
    
    return false;
}


int main()
{
    long long n;
    cin >> n;
   
    cin >> input;
    for (int i = 0; i < 50; i++)
    {
        visit[i] = false;
    }
    backtrace(0, n);
    //for (int j = 0; j < keep.size(); j++)
      //  cout << keep[j] << "aa" << endl;

    cout << ans;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值