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--;
}
}
}
周日坐了一下严禾嘉的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-APAC2015-"super 2048"
- Google-APAC2015-"Password Attacker"
- Google-APAC2015-"New Years Eve"
- Google-APAC2015-"Seven-segment display"
- Google中国2015校园招聘笔试Round D APAC Test Problem B. GBus count
- [Google APAC 2015]Round A.Problem B.Super 2048
- Google中国2015校园招聘笔试Round D APAC Test Problem D. Itz Chess
- Google Code Jam 2015 Round 1A: Problem B. Haircut
- Google中国2015校园招聘笔试Round D APAC Test Problem C. Sort a scrambled itinerary
- Google 2015 APAC Round A Problem C - Addition
- Google Code Jam 2015 Round 1A Haircut 二分
- Google Code Jam Round 1A 2015 Problem B. Haircut
- Catalan数和应用 & 2015 google APAC round 2 problem D 括号配对问题
- Google-APAC2015-Addition (1)
- Google APAC test 2015 Round B Problem A - Password Attacker
- Google APAC test 2015 Round B Problem B - New Years Eve
- Google APAC test 2015 Round B Problem C - Card Game
- Google APAC test 2015 Round B Problem D-Parentheses Order
- Google-APAC2015-Addition (2)
- [ Google APAC 2015 University Graduates Test ] Round C APAC Test