[topcoder]ActivateGame

http://community.topcoder.com/stat?c=problem_statement&pm=10750&rd=14153

http://apps.topcoder.com/wiki/display/tc/SRM+470

因为是棋盘型,然后就想到棋盘型DP;觉得不行,就想到BFS/DFS(这时其实已经把这个看成一张图了)。发现,寻找下一个节点进来的时候,总是要全局考虑所有已经Activate的点,BFS/DFS未果。此时感觉有点像最小生成树的Prim算法,用贪心的,但不知如何证明。此时看了一下题解,发现果然可以规约成最小生成树。因为本质是把棋盘看成一棵树后,整个过程就是Prim的过程。Kruskal的复杂度是O(e*loge),适合求稀疏的图,Prim的复杂度是O(n*n),与边无关,适合求稠密的图。(注:Prim使用堆优化效率可更高。)

Prim算法的讲解:http://www.nocow.cn/index.php/Prim%E7%AE%97%E6%B3%95

参考答案的实现也是O(n*n)的,n为w*h。虽然实现方法和纯粹用邻接表表示的有不同(因为具体问题),但效率并无退化。

我在实现错误的将四个方向的组合从(1,0)这样的搞成了(1,-1)。这表示用两个数组,然后循环遍历,也很简洁。其实里面的变量可以命名为row, col等。

int[] r = new int[] {0, 1, 0, -1};
int[] v = new int[] {1, 0, -1, 0};

代码:

import java.math.*;
public class ActivateGame
{
	public int findMaxScore(String[] grid)
	{
		int h = grid.length;
		int w = grid[0].length();
		boolean[][] activated = new boolean[h][w];
		activated[0][0] = true;
		int[] r = new int[] {0, 1, 0, -1};
		int[] v = new int[] {1, 0, -1, 0};
		int sum = 0;
		for (int cnt = 1; cnt < h*w; cnt++)
		{
			int max = 0;
			int ar = 0;
			int av = 0;
			for (int i = 0; i < h; i++)
			for (int j = 0; j < w; j++)
			{
				if (activated[i][j])
				{
					for (int x = 0; x < 4; x++)
					{
						if (isValid(i+r[x], j+v[x], h, w) && !activated[i+r[x]][j+v[x]])
						{
							int score = Math.abs(getScore(grid[i].charAt(j))-
												getScore(grid[i+r[x]].charAt(j+v[x])));
							if (score > max) 
							{
								max = score;
								ar = i+r[x];
								av = j+v[x];
							}
						}
					}
				}
			}
			sum += max;
			activated[ar][av] = true;
		}
		return sum;
	}	
	private int getScore(char c)
	{
		if (c >= '0' && c <= '9')
		{
			return c - '0';
		}
		else if (c >= 'a' && c <= 'z')
		{
			return c - 'a' + 10;
		}
		else if (c >= 'A' && c <= 'Z')
		{
			return c - 'A' + 36;
		}
		return 0;
	}	
	private boolean isValid(int x, int y, int h, int w)
	{
		return (x >=0 && x< h && y>=0 && y < w);
	}
}

  

原文地址:https://www.cnblogs.com/lautsie/p/3344106.html