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

Google-APAC2015-"cut tiles"

2014-10-29 05:12 351 查看
上个周末在Santa Clara鸡哥家度过。周六早上和鸡哥、严禾嘉还有大师他们一起看了巴萨VS皇马,三个巴萨球迷VS一个巴黑,结果被虐1:3,看得超蛋疼。周六下午4个男人逛街(汗),晚上写了一下代码+看电影。

周日坐了一下严禾嘉的GLK350,推背感蛮明显的。吃早饭的时候,他们谈到:从前以为在硅谷找到一份工作很屌,现在看着银行余额发现钱存起来没那么容易。其实他们是“活得比较明白”的人。饭后去逛了一下Best Buy,果然是湾区标配码农生活模板。

下午自己开车回来,从Santa Clara到UC Davis得开两小时啊,一个人开还是挺寂寞的,突然想起了Nate说的”城市人的孤独“(LOL)。然后我就想起毕业以来在加州居无定所,先是住在Santa Clara,再是Berkeley,最后是UC Davis,一路向北。今天去DMV把宾州的车牌换掉了,上了加州的牌照,突然有那么一丝不舍。

Davis其实我是挺喜欢的,小镇的生活蛮安详,亚洲人却也蛮多,一点也不冷清。在这已经呆了快三个月了。虽然喜欢Davis,但我更想找到一份工作,做到经济独立。

心态已经趋于平静,我觉得再有三次on site的经验”大概估计“会有offer了吧。

anyway,上题:

原题:cut tiles

==============================================================

#1 题目理解

这道题目的意思是,市场上可以购买边长为M的瓷片,装修的时候需要一些边长为2^(s1), 2^(s2), ..., 2^(sk)的小瓷片,可以通过切割边长为M的瓷片获得小瓷片。题目问:最少需要多少块边长为M的瓷片。

test case输入:

1 6 2

2 6 2 2

3 6 2 1 1

7 277 3 8 2 6 1 3 6

每一行的第一个数字表示有多少块小瓷片,第二个数字表示M的大小,后面的数字是小瓷片指数的序列。比如最后一个test case就是M=277,需要切割7块小瓷片,小瓷片序列为{3 8 6 1 3 6}。

test case输出:

Case #1: 1

Case #2: 2

Case #3: 1

Case #4: 2

==============================================================

#2 算法:

// 错误的算法:

开始我认为把一个矩形分割成4部分,但是这样的想法有bug,比如:

6 M=4
{0 2 0 0 1 1}

很明显,这里的答案是{0 0 0 1 1}占用一个边长为4的正方形,{2}占用一个完整的边长为4
的正方形。

接着我又想:如果把一个巨型分割成4部分就会把一个大块的巨型分割成小的。故想着最多把矩形分割成3部分:

 —— —— 
|1 |3 |3 |3
|

 —— —— 

|2 |3 |3 |3
|

 —— ——

|2 |3 |3 |3
|

 —— ——
|2 |3 |3 |3
|

 —— —— 

 如图,编号为“1”的矩形是要分割的矩形,应该分割成为编号为“2”的矩形和编号为“3”的矩形。

 但是后面又发现了这个算法是不可行的,因为事实上,编号为“3”的矩形被分割之后有小片段,和

 编号为“2”的矩形所分割成的小片段可能可以组合成为一个更加大的矩形。

 因此不能使用这种思想去解题。

// 正确的算法:

 事实上使用greedy算法,每次切割的时候保留尽量大的“子方片”就可以了。比如有边长为5的大方片,切割一个边长为2的小方片,应该保留3个边长为2的、9个边长为1的“子方片”。如果接下来要切割一个边长为1的小方片,那么从边长为2的方片切割,切割完之后剩下2个边长为2的、12个边长为1的“子方片”。
注意:一开始要先sort所有的方片,确保从最大的分割。因为看上面的算法描述,如果没有排序过,那么就不能够轻易地区切割目前剩余最大的“子方片”,比如上面描述中的2,因为万一后面又需要边长为2的方片的话,那么就有可能出错。

切割方片的方法:

假设大块方片长度是len,要切割的方片长度是2^t,那么第一次切割,一条边上可能有多个2^t。

N = len / 2^t,有(N * N - 1)个这么大。已经使用的正方形的边长为e = N * 2^t;

那么剩下的材料的一条边最多可以切一个2^(t-1),否则可以继续切割2^t。但是剩下的材料不一定够切割一个2^(t-1),那么假设找到可行的最大是2^s,

可切割出来的数目是2 * e / 2^s + 1。如此切割下去。

==============================================================

#3  数据结构:

tile[31]存Sk为0~30的小方片的数目。
每次需要一个小方片从数组中递减,如果已经为0那么就从tile中较大的方片切割,如果较大的全都用完了就添加新方片。

==============================================================

#4 代码:

import java.util.*;
import java.io.*;

public class Solution {
public static int[] rect = new int[31];

public static void main(String[] args) {
File inFile = new File("D-large-practice.in");
File outFile = new File("D-large-practice.out");
try {
BufferedReader br = new BufferedReader(new FileReader(inFile));
BufferedWriter bw = new BufferedWriter(new FileWriter(outFile));
int T = Integer.parseInt(br.readLine());
for (int i = 1; i <= T; i++) {
String s = br.readLine();
String[] parts = s.split("\\s");
int N = Integer.parseInt(parts[0]);
int M = Integer.parseInt(parts[1]);
int[] tiles = new int
;
for (int j = 0; j < N; j++) {
tiles[j] = Integer.parseInt(parts[j+2]);
}
Arrays.sort(tiles);
// reverse the array, make it descending order
int l = 0, r = tiles.length - 1;
int tmp;
while (l < r) {
tmp = tiles[l];
tiles[l] = tiles[r];
tiles[r] = tmp;
l++;
r--;
}
reset();
bw.write("Case #" + i + ": " + solve(M, tiles) + "\n");
}
bw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

public static int solve(int M, int[] tiles) {
int count = 0;
for (int i = 0; i < tiles.length; i++) {
int t = tiles[i];
int j = 30;
int len; // length of the tile to be cut
while (j >= t) {
if (rect[j] > 0) break;
j --;
}
if (j >= t) {
rect[j] --;
len = pow2(j);
} else {
count ++; // add a new tile
len = M;
}
cut(len, t);
}
return count;
}

// get the length of the tile
public static int pow2(int i) {
int l = 1;
while (i > 0) {
l *= 2;
i --;
}
return l;
}

// reset the rectangle array
public static void reset() {
for (int i = 0; i < 31; i++) {
rect[i] = 0;
}
}

4000
// cut the tile in a greedy way
// 2^t is the length of the tile which is needed
// len is the length of the tile to be cut
public static void cut(int len, int t) {
int n = len / pow2(t);
len = len % pow2(t);
rect[t] += n * n - 1; // add rect's to the array
int e = pow2(t) * n; // the edge of the square which is used
while (t >= 0) {
if (len / pow2(t) > 0) {
rect[t] += 2 * e / pow2(t) + 1;
len -= pow2(t); // update len
e += pow2(t); // update e
}
t--;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  google-apac 算法 Greedy