USACO-section1.3 Combination Lock[枚举]

题意:

锁上有三个转盘,每个上面有数字1..N (1 <= N <= 100),因为转盘是圆的,所以1和N是相邻的。有两种能开锁的号码组合,一种是农夫约翰设定的,还有一种“预设”号码组合是锁匠设定的。但是,锁有一定的容错性,所以,在每个转盘上的数字都与一个合法的号码组合中相应的数字相距两个位置以内时,锁也会打开。
比如说,如果农夫约翰的号码组合是(1,2,3),预设号码组合是(4,5,6),在转盘被设定为(1,4,5)(因为这和农夫约翰的号码组合足够接近)或(2,4,8)(因为这和预设号码组合足够接近)。注意,(1,5,6)并不会打开锁,因为它与任一号码组合都不够接近。
给出农夫约翰的号码组合和预设号码组合,请计算能够开锁的不同的号码组合的数目。号码是有序的,所以(1,2,3)与(3,2,1)不同。

题解:

用三维数组p记录该密码组合是否被试过
[1,n]范围内遍历j,i,k三数,若同时与a或b数组中三个数满足条件,count++,

/* ID:jsntrdy1 PROG: combo LANG: C++ */
#include<cstdio>
#include<iostream>
#include<cstring>
#include<fstream>
#include<cmath>
using namespace std;
const int N=110;
ifstream fin("combo.in");
ofstream fout("combo.out");
bool p[N][N][N];
int n;
//判断密码锁上两个数相距两个单位长度以内 
bool isOK(int a,int b){
    return abs(a-b)<=2||n-abs(a-b)<=2;
}
int main()
{

    fin>>n;
    int a[3],b[3];
    int count=0;
    for(int i=0;i<3;i++)
      fin>>a[i];
    for(int i=0;i<3;i++)
      fin>>b[i];
    for(int j=1;j<=n;j++)
    {
        //剪枝 
        if(!isOK(j,a[0])&&!isOK(j,b[0]))
           continue;
        for(int i=1;i<=n;i++)
        {
            if(!isOK(i,a[1])&&!isOK(i,b[1]))
              continue;
            for(int k=1;k<=n;k++)
            {
                if(!p[j][i][k])
                {
                    if(isOK(j,a[0])&&isOK(i,a[1])&&isOK(k,a[2])||
                    isOK(j,b[0])&&isOK(i,b[1])&&isOK(k,b[2]))
                    {
                      count++;
                      p[j][i][k]=1;
                    }
                }
            }
        }
    }

    fout<<count<<endl;
    cout<<count<<endl;


    return 0;
}
点赞