【发布时间】:2010-04-08 03:27:06
【问题描述】:
简介:
编辑:请参阅此问题底部的解决方案(c++)
我有一个编程竞赛即将举行,我一直在准备:)
我正在练习使用这些问题:
http://cemc.math.uwaterloo.ca/contests/computing/2009/stage2/day1.pdf
我在看问题 B(“晚餐”)。
知道从哪里开始吗?除了天真的方法(即尝试所有排列)之外,我真的想不出任何其他方法,这需要很长时间才能成为有效的答案。
顺便说一句,我认为那里的语言说 c++ 和 pascal,但我不在乎你使用什么语言 - 我的意思是我真正想要的只是关于我应该继续前进的方向的提示,并且可能是一个简短的解释沿着这个走。感觉好像我错过了一些明显的东西......
当然,扩展的猜测是非常受欢迎的,但我只是想澄清一下,我不是在这里寻找完整的解决方案:)
问题的简短版本:
您有一个长度为 1-100 的二进制字符串 N(在问题中,他们使用 H 和 G 而不是一个和 0)。您必须以尽可能少的步骤从中删除所有数字。在每个步骤中,您可以删除任意数量的相邻数字,只要它们相同。也就是说,在每个步骤中,您可以删除任意数量的相邻 G,或任意数量的相邻 H,但不能在一个步骤中删除 H 和 G。
例子:
HHHGHHGHH
例子的解决方法:
1. HHGGHH (remove middle Hs)
2. HHHH (remove middle Gs)
3. Done (remove Hs)
-->Would return '3' as the answer.
请注意,删除相邻组时,相邻组的大小也会受到限制。例如,它可能会说“2”,然后您不能删除单个数字(您必须一次删除对或更大的组)。
解决方案
我使用了Mark Harrison's main algorithm 和Paradigm's grouping idea 并使用它们来创建下面的解决方案。如果您愿意,可以在official test cases 上试用。
//B.cpp
//include debug messages?
#define DEBUG false
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
#define FOR(i,n) for (int i=0;i<n;i++)
#define FROM(i,s,n) for (int i=s;i<n;i++)
#define H 'H'
#define G 'G'
class String{
public:
int num;
char type;
String(){
type=H;
num=0;
}
String(char type){
this->type=type;
num=1;
}
};
//n is the number of bits originally in the line
//k is the minimum number of people you can remove at a time
//moves is the counter used to determine how many moves we've made so far
int n, k, moves;
int main(){
/*Input from File*/
scanf("%d %d",&n,&k);
char * buffer = new char[200];
scanf("%s",buffer);
/*Process input into a vector*/
//the 'line' is a vector of 'String's (essentially contigious groups of identical 'bits')
vector<String> line;
line.push_back(String());
FOR(i,n){
//if the last String is of the correct type, simply increment its count
if (line.back().type==buffer[i])
line.back().num++;
//if the last String is of the wrong type but has a 0 count, correct its type and set its count to 1
else if (line.back().num==0){
line.back().type=buffer[i];
line.back().num=1;
}
//otherwise this is the beginning of a new group, so create the new group at the back with the correct type, and a count of 1
else{
line.push_back(String(buffer[i]));
}
}
/*Geedily remove groups until there are at most two groups left*/
moves=0;
int I;//the position of the best group to remove
int bestNum;//the size of the newly connected group the removal of group I will create
while (line.size()>2){
/*START DEBUG*/
if (DEBUG){
cout<<"\n"<<moves<<"\n----\n";
FOR(i,line.size())
printf("%d %c \n",line[i].num,line[i].type);
cout<<"----\n";
}
/*END DEBUG*/
I=1;
bestNum=-1;
FROM(i,1,line.size()-1){
if (line[i-1].num+line[i+1].num>bestNum && line[i].num>=k){
bestNum=line[i-1].num+line[i+1].num;
I=i;
}
}
//remove the chosen group, thus merging the two adjacent groups
line[I-1].num+=line[I+1].num;
line.erase(line.begin()+I);
line.erase(line.begin()+I);
//we just performed a move
moves++;
}
/*START DEBUG*/
if (DEBUG){
cout<<"\n"<<moves<<"\n----\n";
FOR(i,line.size())
printf("%d %c \n",line[i].num,line[i].type);
cout<<"----\n";
cout<<"\n\nFinal Answer: ";
}
/*END DEBUG*/
/*Attempt the removal of the last two groups, and output the final result*/
if (line.size()==2 && line[0].num>=k && line[1].num>=k)
cout<<moves+2;//success
else if (line.size()==1 && line[0].num>=k)
cout<<moves+1;//success
else
cout<<-1;//not everyone could dine.
/*START DEBUG*/
if (DEBUG){
cout<<" moves.";
}
/*END DEBUG*/
}
一些official test cases你可以试试:
-
测试用例 3
8 2 GHHGHGGH答案:4
-
测试用例 6
20 2 GGHGGHHGGGHHGHHGHHGG答案:6
-
测试用例 14
100 4 HGHGGGHGGGHGHGGGHHGHGGGHHGHHHGHGGHGGHHHGGHHGHHGHGHHHHGHHGGGHGGGHGHGHHGGGHGHGHGGGHHGHHHGHGGGHGGGHGHHH答案:-1
说明:没有正确答案时输出-1。
-
测试用例 18
100 5 GHGGGGGHGGGGGGGHHHHGGGGGHGGHHHGGGGGHHHHGGHHHHHGGGGGGHHHHHHGGGHHHHHGHHGGHHHHHGGGHHGGHHGGGGGGHHHGGGGHH答案:16
-
测试用例 21
95 2 GGHHGGHHGGHHGGHHGGHHGGHHGGHHGGHHGGHHGGHHGGHHGGHHGGHHGGHHGGHHGGHHGHGHGHGHGHGHGHGHGHGHGHGHGHGHGHG答案:32
【问题讨论】:
-
不,很遗憾,除了按照所述执行删除操作之外,您无法移动任何东西。
-
对列表进行排序将使答案始终为 1 或 2,我认为这不是预期的效果。
-
肩膀向下,膝盖着地。
-
它的相邻对的大小使这变得有趣。如果它被固定为 2 或更多,那么@Paradigm 的答案是最好的,但是这些组意味着您需要按正确的顺序将足够的字母放在一起才能删除它们。
标签: algorithm language-agnostic