USACO Section 1.3 Combination Lock

题目原文

Combination Lock

Farmer John's cows keep escaping from his farm and causing mischief. To try and prevent them from leaving, he purchases a fancy combination lock to keep his cows from opening the pasture gate.

Knowing that his cows are quite clever, Farmer John wants to make sure they cannot easily open the lock by simply trying many different combinations. The lock has three dials, each numbered 1..N (1 <= N <= 100), where 1 and N are adjacent since the dials are circular. There are two combinations that open the lock, one set by Farmer John, and also a "master" combination set by the lock maker. The lock has a small tolerance for error, however, so it will open even if the numbers on the dials are each within at most 2 positions of a valid combination.

For example, if Farmer John's combination is (1,2,3) and the master combination is (4,5,6), the lock will open if its dials are set to (1,N,5) (since this is close enough to Farmer John's combination) or to (2,4,8) (since this is close enough to the master combination). Note that (1,5,6) would not open the lock, since it is not close enough to any one single combination.

Given Farmer John's combination and the master combination, please determine the number of distinct settings for the dials that will open the lock. Order matters, so the setting (1,2,3) is distinct from (3,2,1).

PROGRAM NAME: combo

INPUT FORMAT:

Line 1:The integer N.
Line 2:Three space-separated integers, specifying Farmer John's combination.
Line 3:Three space-separated integers, specifying the master combination (possibly the same as Farmer John's combination).

SAMPLE INPUT (file combo.in):

50
1 2 3
5 6 7

INPUT DETAILS:

Each dial is numbered 1..50. Farmer John's combination is (1,2,3), and the master combination is (5,6,7).

OUTPUT FORMAT:

Line 1:The number of distinct dial settings that will open the lock.

SAMPLE OUTPUT (file combo.out):

249

分析

题目很简单,一把密码锁,有两个解锁的数字组合,数字的范围在1~N之间,而N是小于100的正整数,并且数字是循环的,N+1就是1
例如1 2 3和5 6 7,但是由于密码锁有一定的误差,所以每一位的数字都可以与密码相差2,例如(3 6 8)与(5 6 7)接近,所以可以打开,要求求出总共有多少种组合可以打开密码锁。
直接穷举即可,循环次数为5*5*5=125次,关键是要把重复的剔除掉,还是以上面的例子为例,(3 4 5)同时满足(1 2 3)和(5 6 7)。
重复组合的剔除可以自己实现,也可以直接使用STL的set容器,set容器可以确保每一个元素的唯一性。

实现代码

 /*
 ID: 
 PROG: combo
 LANG: C++
 */

 #include <fstream>
 #include <iostream>
 #include <set>
#include <vector>
 using namespace std;





 int main()
 {
 	ifstream fin("combo.in");
 	ofstream fout("combo.out");

 	int N;
 	fin >> N;
 	std::vector<int> combo1(3);
 	std::vector<int> combo2(3);

 	fin >> combo1[0] >> combo1[1] >> combo1[2];
 	fin >> combo2[0] >> combo2[1] >> combo2[2];


 	set<std::vector<int>> combo_set;

 	for (int i = -2; i <= 2; ++i)
 	{
 		for (int j = -2; j <= 2; ++j)
 		{
 			for (int k = -2; k <= 2; ++k)
 			{
 				std::vector<int> v(3);
 				v[0] = (i+combo1[0]+N)%N;
 				v[1] = (j+combo1[1]+N)%N;
 				v[2] = (k+combo1[2]+N)%N;

				std::vector<int> v1(3);
				v1[0] = (i+combo2[0]+N)%N;
				v1[1] = (j+combo2[1]+N)%N;
				v1[2] = (k+combo2[2]+N)%N;

				combo_set.insert(v);
				combo_set.insert(v1);
 			}
 		}
 	}

	fout << combo_set.size() << endl;

	return 0;



 }

提交结果

TASK: combo
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.008 secs, 3500 KB]
   Test 2: TEST OK [0.011 secs, 3500 KB]
   Test 3: TEST OK [0.016 secs, 3500 KB]
   Test 4: TEST OK [0.005 secs, 3500 KB]
   Test 5: TEST OK [0.005 secs, 3500 KB]
   Test 6: TEST OK [0.005 secs, 3500 KB]
   Test 7: TEST OK [0.005 secs, 3500 KB]
   Test 8: TEST OK [0.005 secs, 3500 KB]
   Test 9: TEST OK [0.005 secs, 3500 KB]
   Test 10: TEST OK [0.008 secs, 3500 KB]

All tests OK.

官方的参考答案

#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;

int N;

bool close(int a, int b)
{
  if (abs(a-b) <= 2) return true;
  if (abs(a-b) >= N-2) return true;
  return false;
}

bool close_enough(int n1, int n2, int n3,
		  int c1, int c2, int c3)
{
  return close(n1,c1) && close(n2,c2) && close(n3,c3);
}

int main(void)
{
  int f1, f2, f3;
  int m1, m2, m3;

  ifstream fin("combo.in");
  fin >> N;
  fin >> f1 >> f2 >> f3;
  fin >> m1 >> m2 >> m3;
  fin.close();

  int total = 0;
  for (int n1=1; n1<=N; n1++)
    for (int n2=1; n2<=N; n2++)
      for (int n3=1; n3<=N; n3++)
	if (close_enough(n1,n2,n3,f1,f2,f3) ||
	    close_enough(n1,n2,n3,m1,m2,m3))
	  total++;

  ofstream fout("combo.out");
  fout << total << "\n";
  fout.close();

  return 0;
}

官方参考答案也是穷举法,不过其循环次数是N的三次方,个人认为本文提供的方法更优。

THE END


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值