Code Jam 2009 Qualification :: 我去打酱油

Code Jam 2009今天进入了资格赛,我算法很弱...纯粹属于打酱油去的选手...

简单说明一下资格赛的题目,一共有3道题目:

1. Alien Language (外星语)

题目大致的意思是,人类掌握了一本外星语字典,然后手头上有部分外星语的碎片看不清楚,其中某些字符可能是多个字符中的一个,要你根据已经掌握的字典计算外星语碎片上的文字共有多少种可能性。


简单举个例子,目前掌握了如下的外星语文字,即字典:

abc
bca
dac
dbc
cba

那么,对于一个给定的输入(ab)(bc)(ca)——其中()中的字母代表这个位置上可能是()中的某一个字符,有可能在字典中的匹配是abc和bca,也就是有2个匹配。

我做的思路是这样的:

首先根据字典建立一个N叉树,如下图(没有画完整),其中R代表Root。

2009-09-03_215618
对于一个给定的输入,比如(ab)(bc)(ca),则准备一个queue,先将Root放入queue,进入循环,每次从queue中拿出一个node,在这个node下找是否有匹配,若有,则把这些节点放到queue中,直到匹配完整个字符串,在queue中剩下的node数就是可能产生的匹配数。

按理来说,这个算法的复杂度,建树为O(L * D)(L为每个文字的长度,D为字典的大小),在树上搜索为O(M * N) (M为需要匹配的文字的最大长度,N为需要匹配的文字数),那么总的复杂度就是O(L * D + M * N)。但是大概是我的实现太撮...导致Time expire...所以Small Case过了,Large Case failed...

2. Watersheds

这个题目就是给你一个N*N个Cell的地图,地图上每个Cell标注了它的海拔。然后水流从海拔高的Cell将流向海拔低的Cell,每个Cell可以有多条水流入,但只有上、下、左、右中的一个方向可以流出。同一条水流路径上面的Cell被用同一个字符标记,然后标记的顺序也有个讲究,具体请自己看题目,在最后给出。

具体解决思路是:从左上角开始,依次对每一个没有标记过的Cell做rec_mark操作,这个操作首先判断当前这个点是否为Sink(也就是局部最低点),若是则进行标记,若不是,则往最低的方向递归调用rec_mark。

这道题目倒是很顺利,一下就过了。

3. Welcome to Code Jam

这道题目很常规,让你在一个目标字符串中查找某一个固定的pattern出现了多少次,比如

elcomew elcome to code jam

这个字符串中,只有一个子串符合welcome to code jam这个pattern,故输出为1.

我开始写这个算法的时候低估了他递归的层次深度,结果没有用动态规划,直接递归了...在small case的时候没问题,我就很兴奋直接上了large case,结果么...fail了...郁闷...

后来加了一个table记录子问题的答案后,就顺利算出结果了,不过么...也来不及了...

总的来说,这次酱油打得不是非常体面,下次我还是做做围观群众吧...

附题目:

问题1

2009-09-03_224010

问题2

2009-09-03_224107

问题3

2009-09-03_223914

我的代码,很土...

问题1
C
#include <iostream>
#include <fstream>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <queue>
 
using namespace std;
 
struct t_node
{
	map<char, t_node*> m_nodes;
 
	~t_node()
	{
		if (!m_nodes.empty())
		{
			for (map<char, t_node*>::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
			{
				delete it->second;
			}
		}
	}
};
 
 
ifstream fin("c:\\A-large.in");
ofstream fout("c:\\A-large.out");
 
#define cin fin
#define cout fout
 
int main()
{
	int L;
	int D;
	int N;
	cin >> L >> D >> N;
	t_node root;
	t_node *p_node;
	// Build tree
	for (int d = 0; d < D; ++d)
	{
		string word;
		cin >> word;
		p_node = &root;
		for (int l = 0; l < L; ++l)
		{
			if (p_node->m_nodes.find(word[l]) == p_node->m_nodes.end())
			{
				// Insert char->node pair to m_nodes
				p_node->m_nodes[word[l]] = new t_node;
			}
			p_node = p_node->m_nodes[word[l]];
		}
	}
	// Matching cases
	for(int n = 0; n < N; ++n)
	{
		string line;
		cin >> line;
		queue<t_node *> possible_matches;
		possible_matches.push(&root);
		for (string::size_type pos = 0; !possible_matches.empty() && pos < line.length(); ++pos)
		{
			queue<t_node *>::size_type n_matches = possible_matches.size();
			int chars_begin = pos;
			int chars_end;
			if (line[pos] == '(')
			{
				chars_begin++;
				chars_end = line.find_first_of(')', chars_begin);
				pos = chars_end;
			}
			else
			{
				chars_end = chars_begin + 1;
			}
			for (queue<t_node *>::size_type i = 0; i < n_matches; ++i)
			{
				t_node *this_node = possible_matches.front();
				possible_matches.pop();
				for (int char_pos = chars_begin; char_pos != chars_end; ++char_pos)
				{
					char ch = line[char_pos];
					if (this_node->m_nodes.find(ch) != this_node->m_nodes.end())
					{
						possible_matches.push(this_node->m_nodes[ch]);
					}
				}
			}
		}
		cout << "Case #" << n + 1 << ": " << possible_matches.size() << endl;
	}
	return 0;
}
问题2
C
#include <iostream>
#include <string>
#include <fstream>
 
using namespace std;
 
#define MAX_H	100;
#define MAX_W	100;
 
ifstream fin("C:\\B-large.in");
ofstream fout("C:\\B-large.out");
 
#define cin fin
#define cout fout
 
int map[100][100] = {0};
char mark[100][100] = {0};
 
int W;
int H;
 
char ch_mark;
 
int rec_mark(int r, int c)
{
	if (mark[r][c] != 0)
	{
		return mark[r][c];
	}
	else
	{
		// Calculate diff of altitude
		int up, left, right, down;
		up = left = right = down = -1;
		if (r > 0)
		{
			up = map[r][c] - map[r-1][c];
		}
		if (c > 0)
		{
			left = map[r][c] - map[r][c-1];
		}
		if (c < W - 1)
		{
			right = map[r][c] - map[r][c+1];
		}
		if (r < H - 1)
		{
			down = map[r][c] - map[r+1][c];
		}
		if (up <= 0 && left <= 0 && right <= 0 && down <= 0)
		{
			// Sink
			mark[r][c] = ch_mark;
			ch_mark++;
		}
		else
		{
			// Find the flow direction
			int max_diff = up;
			int dr = -1; int dc = 0;
			if (left > max_diff)
			{
				max_diff = left;
				dr = 0; dc = -1;
			}
			if (right > max_diff)
			{
				max_diff = right;
				dr = 0; dc = 1;
			}
			if (down > max_diff)
			{
				dr = 1; dc = 0;
			}
			if (mark[r + dr][c + dc] != 0)
			{
				mark[r][c] = mark[r + dr][c + dc];
			}
			else
			{
				mark[r][c] = rec_mark(r + dr, c + dc);
			}
		}
		return mark[r][c];
	}
}
 
int main()
{
	int N;
	cin >> N;
 
	for (int n = 0; n < N; ++n)
	{
		ch_mark = 'a';
		int a;
		cin >> H >> W;
		for (int i = 0; i < H; ++i)
		{
			for (int j = 0; j < W; ++j)
			{
				cin >> a;
				map[i][j] = a;
				mark[i][j] = 0;
			}
		}
		// Look for next cell to eval
		for (int r = 0; r < H; r++)
		{
			for (int c = 0; c < W; c++)
			{
				if (mark[r][c] == 0)
				{
					rec_mark(r, c);
				}
			}
		}
		cout << "Case #" << n + 1 << ":" << endl;
		for (int r = 0; r < H; r++)
		{
			for (int c = 0; c < W; c++)
			{
				cout << mark[r][c] << ' ';
			}
			cout << endl;
		}
	}
	return 0;
}
问题3
C
#include <iostream>
#include <string>
#include <fstream>
 
using namespace std;
 
int n_src;
string src;
const int n_ptrn = 19;
const string ptrn = "welcome to code jam";
 
ifstream fin("C:\\C-small-attempt0.in");
 
#define cin fin
 
FILE *file;
 
int tbl[512][32];
 
int find_substring(const int s_src, const int s_ptrn)
{
	if (tbl[s_src][s_ptrn] != -1)
	{
		return tbl[s_src][s_ptrn];
	}
	if (n_src - s_src < n_ptrn - s_ptrn)
	{
		tbl[s_src][s_ptrn] = 0;
		return 0;
	}
	if (n_src - s_src == n_ptrn - s_ptrn)
	{
		string sub_src = src.substr(s_src, n_src - s_src);
		string sub_ptrn = ptrn.substr(s_ptrn, n_ptrn - s_ptrn);
		tbl[s_src][s_ptrn] = (sub_src == sub_ptrn) ? 1 : 0;
		return tbl[s_src][s_ptrn];
	}
	int total = 0;
	// Skip current char
	total += find_substring(s_src+1, s_ptrn);
	total %= 10000;
	// If current char matches
	if (src[s_src] == ptrn[s_ptrn])
	{
		total += find_substring(s_src+1, s_ptrn+1);
		total %= 10000;
	}
	tbl[s_src][s_ptrn] = total;
	return total;
}
 
int main()
{
	file = fopen("C:\\a.out", "w");
	int N;
	cin >> N;
	getline(cin, src);
	for (int n = 0; n < N; ++n)
	{
		getline(cin, src);
		memset(tbl, -1, sizeof(tbl));
		n_src = src.length();
		int cnt = find_substring(0, 0);
		fprintf(file, "Case #%d: %04d\n", n+1, cnt);
	}
	return 0;
}

Comments (11)

  1. 05:35, 2009-09-04ChrisPei  / Reply

    刚弄完。由于最后一题有点郁闷搜到你这来了,同样是一兴奋,弄large case。结果一样。直接递归使得我跑了10多分钟连第二个case都没有算出来。最后跑到整型溢出……Google真够狠的。

    BTW,我英文名也叫Chris,呵呵。

  2. 09:15, 2009-09-04Poshi  / Reply

    也太長了吧~~~

  3. 09:19, 2009-09-04Justice  / Reply

    @Poshi
    哈,Chris是大师啊~

  4. 12:28, 2009-09-04koh  / Reply

    崇拜一下。。。大牛啊。。。

  5. 13:44, 2009-09-04Chris  / Reply

    @ChrisPei
    哇,弄到5点半...我看了一下他的test case,第一个case是故意让你的程序反复解同一些子问题...所以不用动态规划的话基本上第一个case就跑不过,太阴险了,呵呵

  6. 13:45, 2009-09-04Chris  / Reply

    @Poshi
    主要是后面的code太长了,其实正文一点点,呵呵

  7. 13:46, 2009-09-04Chris  / Reply

    @Justice
    那你是大er牛

  8. 13:48, 2009-09-04Chris  / Reply

    @koh
    小胖子你啥时候回学校啊?

  9. 14:48, 2009-09-04koh  / Reply

    @Chris
    周末

  10. 19:57, 2009-09-05Solluna  / Reply

    a? 第一题large case过不了啊?那就给每个树节点弄个26的数组吧?空间换取时间~反正现在内存不值钱╮(╯▽╰)╭

  11. 20:35, 2009-09-05Chris  / Reply

    @Solluna
    小明的idea为正解,囧~

Leave a Reply

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

Pingbacks (0)

› No pingbacks yet.