7-5 Equivalent Passwords (等效密码) (10 分)

7-5 Equivalent Passwords (等效密码) (10 分)

题目

Yesterday you arrived at the hotel, and you kept all your valuable stuff in your room’s safe. Unfortunately, you forgot the password. But you have a very long list of passwords (each password is at most 5 digits), and you are sure that your password is one of them.

昨天你到达酒店,把所有贵重物品都放在房间的保险箱里。不幸的是,你忘了密码。但是你有一个很长的密码列表(每个密码最多是5位数字),而且你要确定你的密码就是其中之一。

The safe will consider some passwords equivalent. Two passwords A and B are considered equivalent, if they are of the same length, and |A[i] - B[i]| is the same for all possible values of i, where X[i] is the i-th digit of X and |Y| is the absolute value of Y.

保险柜会考虑一些等效的密码。两个密码A和B的长度相同,|A[i] - B[i]|对于i的所有可能值都相同,其中X[i]是X的第 i 位,|Y|是Y的绝对值。

You will go through the list of passwords in the given order. For each password, you will do the following:

您将按照给定的顺序遍历密码列表。对于每个密码,您将执行以下操作:

1.If the same password or any of its equivalent passwords were typed before, skip this password.

2.Otherwise, type this password into the safe.

3.If it’s the correct password (or any of its equivalent passwords), the safe will open and you will stop any further processing.

如果之前输入了相同的密码或任何等效的密码,请跳过此密码。

否则,请在保险箱中键入此密码。

如果它是正确的密码(或任何与其相当的密码),保险箱将打开,您将停止任何进一步的处理。

Now given the list of all passwords, you would like to know, in the worst case scenario, what is the maximum number of passwords you will have to type?

现在给出了所有密码的列表,您想知道,在最坏的情况下,您必须键入的最大密码数量是多少?

Note

In the first test case: 在第一个测试用例中:

all passwords are equivalent to each other. This means that the first password will open the safe for sure.

所有密码彼此相等。这意味着第一个密码将肯定打开保险箱。

In the second test case: 在第二个测试用例中:

If the first password is the correct one, you will type 1 password.
If the second password is the correct one, you will type 2 passwords.
If the third password is the correct one, you will type 2 passwords (because the second password is equivalent to the third one).
If the fourth password is the correct one, you will type 1 password (because the first password is equivalent to the fourth one).
如果第一个密码是正确的,您将键入1个密码。
如果第二个密码是正确的,您将键入2个密码。
如果第三个密码是正确的,您将键入2个密码(因为第二个密码是相当于第三个)。
如果第四个密码是正确的,您将键入1个密码(因为第一个密码是相当于第四个)。
In the third test case: 在第三个测试用例中:

If the first password is the correct one, you will type 1 password.
If the second password is the correct one, you will type 1 password (because the first password is equivalent to the second one).
If the third password is the correct one, you will type 2 passwords. Even though the third password is equivalent to the second password, the second password was skipped, and therefore you should type the third password.
如果第一个密码是正确的,你将输入一个密码。
如果第二个密码是正确的,您将键入1个密码(因为第一个密码等于第二个密码)。
如果第三个密码是正确的,你将输入2个密码。尽管第三个密码相当于第二个密码,但第二个密码被跳过,因此应该跳过输入第三个密码。

输入

Your program will be tested on one or more test cases. The first line of the input will be a single integer T(1 ≤ T ≤ 50) representing the number of test cases.

您的程序将在一个或多个测试用例上进行测试。输入的第一行是一个整数T(1≤T≤50)表示测试用例的数量。

Followed by T test cases. Each test case starts with a line will containing an integer N (1 ≤ N ≤ 100,000) representing the number of passwords, followed by N lines, each one will contain a non-empty string of at most 5 digits (from ‘0’ to ‘9’), representing a password (might contain leading zeros).

接下来是T测试用例。每个测试用例开始的一行将包含一个整数N(1≤N≤100,000),表示密码的数量,然后是N行,每个行将包含一个不超过5位的非空字符串(从‘0’到‘9’),表示一个密码(可能包含前导零)。

输出

For each test case print a single line containing “Case n: ” (without quotes) where n is the test case number (starting from 1) followed by a space then the maximum number of passwords you will have to type.

对于每个测试用例,打印包含“case n: ”(不带引号)的单行代码,其中n是测试用例号(从1开始)后面跟着空格,然后是你需要输入的最大密码数。

Sample Input

3
3
000
111
222
4
1111
123
214
2222
3
43434
54545
45454

Sample Output

Case 1: 1
Case 2: 2
Case 3: 2

基本思路

这是一道隐式树的dfs问题。
在每一组测试样例中,每读入一个密码,如果这个密码没有出现过,就通过dfs求出它的所有等效密码,然后将这些等效密码置为已出现过,并使计数器加一;如果这个密码出现过,则直接跳过。最后输出这一组测试样例下需要输入密码的最大次数。
注意:每一组测试样都需要把数组exsit重新初始化,防止不同测试样例间的等效密码产生干扰。

代码

#include <bits/stdc++.h>
using namespace std;

int t,nn;//测试样例组数,每组测试样例的密码个数
string password;//密码(可以是字符串,也可以是整数)

int exsit[6][100000];//exsit[][]代表一个密码(以及它的等效密码)是否出现过,第一个[]存放密码长度,第二个[]存放密码。默认初始化为0
int pos[6];//存放数字字符串password
int posAfterDFS[6];//存放数字字符串password的等效字符串

void dfs(int d,int n,int abs){
    //如果d==n,说明遇到了递归边界,也求出了一个等效密码,取出该密码并把该密码置为已出现过
    if(d==n){
        int sum = 0;
        for (int i = 0; i < n;i++){
            sum = sum * 10;
            sum += posAfterDFS[i];
        }
        exsit[n - 1][sum] = 1;
        return;
    }
    //如果当前位d加上abs后未越界,就把pos[d] + abs放到posAfterDFS[d],并对d+1位进行dfs
    if(pos[d]+abs<=9){
        posAfterDFS[d] = pos[d] + abs;
        dfs(d + 1, n, abs);
    }
    //如果当前位d减去abs后未越界,就把pos[d] - abs放到posAfterDFS[d],并对d+1位进行dfs
    if (pos[d] - abs >= 0){
        posAfterDFS[d] = pos[d] - abs;
        dfs(d + 1, n, abs);
    }
}
void markEuqal(string password){
    //将字符串password转换成整型数组pos
    for (int i = 0; i < password.length();i++){
        pos[i] = password[i] - '0';
    }
    //因为等效密码之间每一对应位的差可以为1~9
    //所以枚举i从1到9,对每一个差进行一轮dfs
    //每一轮dfs求出这一差值下的若干个等效密码(在每一个递归边界处会有一个等效密码存放在数组posAfterDFS),置它为们已出现过
    for (int i = 1; i <= 9; i++){
        dfs(0, password.length(), i); //实参:password的下标(从0开始),password的长度,这一轮dfs中等效密码之间每一对应位的差值
    }
}
int main(){
    cin>>t;
    for(int i=1;i<=t;i++){
        cin>>nn;
        //初始化数组exsit,防止不同测试样例间的等效密码之间产生干扰
        memset(exsit, 0, sizeof (exsit));
        int cnt=0;//计数器,记录输入密码的最大次数
        //每读入一个密码,判断这个密码(以及等效密码)是否出现过
        //如果没有出现过,则把这个密码(以及等效密码)置为出现过,并使计数器加一
        while(nn--){
            cin>>password;
            if(exsit[password.length()-1][stoi(password)]==0){
                exsit[password.length()-1][stoi(password)]=1;
                markEuqal(password);
                cnt++;
            }
        }
        printf("Case %d: %d\n",i,cnt);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值