您的位置:首页 > 其它

POJ 1012: Joseph

2015-03-12 11:10 176 查看
解题要点 1: 必须剪枝以避免地毯式搜索.

考虑一个满足题设条件的 m, 在处决了 k - 1 个坏人之后, 剩下的还有 k 个好人以及 1 个坏人, 共 k + 1 个人. 同时考虑到刚刚被处决的坏人必然在剩下的唯一 1 个坏人身边, 或前或后, 因此最后一轮循环的起点要么是剩下的唯一 1 个坏人, 要么是第 1 个好人, 且最后一轮循环的终点是剩下的唯一 1 个坏人. 由此可以推知, m 必定是一个满足以下条件的自然数:

m = ( k + 1 ) * i 或 m = ( k + 1 ) * i + 1, 其中 i = 1, 2, …

只对这些可能满足条件的 m 进行检测, 即可避免地毯式搜索.

解题要点 2: 必须制表以应对狡猾的裁判.

经上一步优化后的代码仍然会 TLE. 为了寻找原因, 考虑到题目已经限定了 0 < k < 14, 因而可以很方便地对全部可能的输入进行测试. 测试后立即会发现, 当 k = 13 时, 尽管 m 已经达到了 1,000,000 的数量级, 但计算速度仍然飞快. 由此可以想到导致 TLE 的唯一可能就是裁判在测试数据里放置了海量的 13…

由于每个 k 都对应一个确定的 m, 因此只要在第一次计算时把结果存到一个阵列里, 就可以破解狡猾裁判的陷阱.

代码如下:

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

bool joseph( const int& k, const int& m ) {
int n = k * 2, beg = -1;
for( int i = 0; i < k; ++i ) {
if( ( beg + m ) % n < k ) {
return false;
}
beg = ( beg + m - 1 ) % ( n-- );
}
return true;
}

int main() {
vector<int> result( 15, 0 );
int k, m;
while( cin >> k && k != 0 ) {
if( result[k] != 0 ) {
cout << result[k] << endl;
continue;
}
for( int i = 1; ; ++i ) {
m = ( k + 1 ) * i;
if( joseph( k, m ) || joseph( k, ++m ) ) {
result[k] = m;
cout << m << endl;
break;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: