您的位置:首页 > 编程语言 > Go语言

ACM-GOOGLE CODE JAM 2011 Qualification Round 2011(总结)

2011-05-10 18:55 423 查看
上周末,我分别参加了CODE
JAM的资格赛和北大的PKU比赛,正规的ACM比赛都是我第一次参加,中间也经历了很多的问题和磨难,打算分几次来写写自己的心得吧。

CODE JAM比赛是在线的比赛,必须提交测试数据集的运行结果和源代码。测试数据集分两种,一种small数据集,一种是large数据集。

第一题:http://code.google.com/codejam/contest/dashboard?c=975485#

题目大意是,A、B两个机器人在长廊中协作完成一个指定系列顺序的任务,机器人每移动一格需要一秒,按下一个按钮也需要一秒,必须严格按照指定系列完成任务,问最短完成的时间是多少?

还是比较简单的吧,可以声明两个数组atime 和 btime
分别代表A、B完成下一个任务时的时间,则可以得到这样一个结论,atime[afinal] = max( atime[alast] + amove ,
btime[bfinal])
+ 1;代表意思是机器人A完成最新任务的时间为机器人A上一次的时间加上移动到当前任务位置的时间,或者是A移动到当前任务位置以后等待B完成最新任务以后的时间,加上执行任务的时间。同样道理btime[bfinal]
= max(btime[blast] + bmove, atime[afinal]) +1;

代码如下:

#include <iostream>
#include <fstream>
#include <math.h>
#define  max(a,b) (a)>(b)?(a):(b)
using namespace std;
const int SIZE =101;
ifstream fin("bot_large.in");
ofstream fout("bot_large.out");
int cas;
int index =1;
int step = 0;
int b[SIZE] = {0};
int bl =0;
int bp = 1;
int o[SIZE] = {0};
int ol=0;
int op = 1;
void omove(int p)
{
int move = abs(p-op)+1+o[ol-1];
o[ol] = max( move, b[bl-1]+1);
ol ++;
op = p;
}
void bmove(int p)
{
int move = abs(p-bp)+1+b[bl-1];
b[bl] = max(move, o[ol-1]+1);
bl ++;
bp = p;
}
void read()
{
bp = 1;
op = 1;
bl = 1;
ol = 1;
b[0] =0;
o[0] =0;
fin >> step;

char r;
int p;
for (int i =0; i < step; i ++)
{
fin >> r >> p;

if (r == 'O')
{
omove(p);
}
else
{
bmove(p);
}
}//end for

int result = max(o[ol-1], b[bl-1]) ;
fout << "Case #" << index << ": "  << result << endl;
}

int main()
{
fin >> cas;
while (index <= cas)
{
read();
index ++;
}
return 0;
}


第二题:http://code.google.com/codejam/contest/dashboard?c=975485#s=p1

题目大意是,一种游戏,有8个原字母,不断的添加字母,如果两个字母出现在组合逻辑中,则合并成新的字母,如果不能合并,则判断字母是否出现在排斥队列中,如果是的话,则消除整个队列(这个很重要,我第一次理解成了删除两个字母之间的所有字母)。

我的做法是建立两个二维数组,combine[i][j] = combine[j][i] = NEWCHA,表示i,j字母可以融合成新的字母,opp[i][j] = opp[j][i] = 1表示字母i到j互相排斥。则读取一个系列的时候,先判断合并,再判断是否可以消除。题目理解对了,就相对比较简单了,复杂的数据量也没有问题。

代码如下:

#include<iostream>
#include<fstream>
#include <string.h>
using namespace std;
const int SIZE = 26;
const int N  = 101;
ifstream fin("mag_large.in");
ofstream fout("mag_large.out");
int cas, index = 1;
int c, d, n;
int str[101];
int length;
int combine[SIZE][SIZE];
int oppose[SIZE][SIZE];
void cmbop()
{
int a, b;
if (length>1)
{
a =str[length-2];
b = str[length-1];
if (combine[a] != 0)
{
str[length-2] = combine[a][b];
length --;
return;
}//end if
}
a = str[length-1];
for (int i=0; i <= length-2; i ++)
{
b = str[i];
if (oppose[a][b] == -1)
{
length = 0;
break;
}
}
}

void read()
{
memset(combine, 0, sizeof(int) * SIZE * SIZE);
memset(oppose, 0, sizeof(int) * SIZE * SIZE);
fin >> c;
char c1, c2, c3;
for (int i=0; i < c; i ++)
{
fin >> c1 >> c2 >> c3;
combine[c1 - 'A'][c2- 'A'] = c3 - 'A';
combine[c2-'A'][c1-'A'] = c3-'A';
}
fin >> d;
int i;
for (i=0; i < d; i ++)
{
fin >> c1 >> c2;
oppose[c1-'A'][c2-'A'] =  -1;
oppose[c2-'A'][c1-'A'] = -1;
}

length = 0;
fin >> n;
char cha;
for (i=0; i< n; i ++)
{
fin >> cha;
str[length] = cha - 'A';
length ++;
cmbop();
}
}
void print()
{
fout<< "Case #" << index <<": [";
if (length>0)
{
char c = 'A' + str[0];
fout << c;
}
for (int i=1; i < length; i ++)
{
char c = 'A' + str[i];
fout << ", " << c;
}
fout << "]" << endl;
}

int main()
{
fin >> cas;
while (index <= cas)
{
read();
print();
index ++;
}
return 0;
}


第三题:http://code.google.com/codejam/contest/dashboard?c=975485#s=p2

题目大意是:两个儿子在分糖果,然后小儿子比较笨,只会用异或的办法求和,只要小儿子觉得两边的糖果相等,就不会哭。然后要求大儿子在不把小儿子弄哭的情况下,分糖果,并且保证自己的糖果序号和最大。

第一次看到这道题的时候,由于小数据量不大,2 ≤ [b]N
≤ 15.因此我使用的方法是采用0-1遍历的方法,0代表不取,1代表取。遍历出所有的情况,最后进行判断。

代码如下:

#include<iostream>
#include <fstream>

using namespace std;
ifstream fin("candy.in");
ofstream fout("candy.out");
const int SIZE = 1000;
int cas, index=1;
int n;
int arr[SIZE];
int path[SIZE];
int csum;
int cpsum;
int psum;
int pcsum;
int result =0;
void read()
{
fin >> n;
for (int i=0; i < n; i ++)
{
fin >> arr[i];
}

result =0;
}
void candy(int c)
{
if (c >= n)
{
csum = 0;
psum = 0;
cpsum =0;
pcsum = 0;
for (int i=0; i< n; i ++)
{
if (path[i] == 0)
{
csum += arr[i];
cpsum = cpsum^arr[i];
}
else
{
pcsum += arr[i];
psum = psum ^ arr[i];
}
}
if (cpsum == psum&&pcsum!=0)
{
if (result < csum)
{
result = csum;
}
}
return;
}
path[c] = 0;
candy(c+1);
path[c] =1;
candy(c+1);
}
void print()
{
if (result == 0)
{
fout << "Case #" << index<<": NO"<<endl;
}
else
fout <<"Case #"<<index<<": "<<result<<endl;
}
int main()
{
fin >> cas;

while (index <= cas)
{
read();
candy(0);
print();
index ++;
}
return 0;
}


但是对于大数据量来说,复杂度为2^n,明显过不了。因此,但是分析一下,假设原系列为A1, A2,A3,……An。那么小儿子觉得相等的情况为Ai ^ Aj ^ Ak ^ …… = Ax ^ Ay ^ Az ^ ……。那么也就是说,如果糖果是可分的话,A1 ^ A2 ^ A3 ……= 0,那么两边同时异或最小的数 A1^A2 ^ A3^ ……^An = Amin,因此,如果整个异或为0,则只要所有数求和减去最小的数,就是结果了,代码如下:

#include<iostream>
#include <fstream>

using namespace std;
ifstream fin("candy_large.in");
ofstream fout("candy_large.out");
const int SIZE = 1000;
int cas, index=1;
int n;
int arr[SIZE];
int result =0;
void read()
{
fin >> n;
for (int i=0; i < n; i ++)
{
fin >> arr[i];
}
result =0;
}
void candy()
{
int small = 0x7fffffff;
int psum = 0;
for (int i=0; i<n; i ++)
{
if (arr[i] < small)
{
small = arr[i];
}
psum = psum ^ arr[i];
result += arr[i];
}
if (psum == 0)
{
result -= small;
}
else
result = 0;
}
void print()
{
if (result == 0)
{
fout << "Case #" << index<<": NO"<<endl;
}
else
fout <<"Case #"<<index<<": "<<result<<endl;
}
int main()
{
fin >> cas;
while (index <= cas)
{
read();
candy();
print();
index ++;
}
return 0;
}


最后一题比较复杂,下回单独说吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: