试题 C: 切割
本题总分:10 分
【问题描述】
在 4×4 的方格矩阵中画一条直线。则直线穿过的方格集合有多少种不同的
可能?
这个里直线穿过一个方格当且仅当直线将该方格分割成面积都大于 0 的两
部分。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
这个题网上没有找到大佬解决,硬着头皮自己试了半天。最后采用坐标系,进行筛选判断。
看图,分成16格,每个格子给它起个名字,任意起名字。
首先,它肯定是有旋转性质的,我们先求出一边的结果数,就能直接得出4边的多少种。我把每一格分成100刻度,当然分的更多更精确。
判断该直线上每一点坐标在哪个区间,然后收集格子上的字符,采用判重只收集一次。
收集完之后存入set,累计数量。
任意一点坐标怎么求,这都是数学的基本公式了,利用y轴刻度 y 作为参照(0~400),那么对应x坐标为:double x = x2 + (x1 - x2) / 400 * y;
最外层遍历x1(0~400),x2(0~400)。时间复杂度n^3。
固定x1=0不变,然后x2和y均为(0~400)遍历,收集,和(1)类似
固定x1=400不变,然后x2和y均为(0~400)遍历,收集,和(2)一样
最后得到结果:
1
15
159
159d
2
21
215
2159
2159d
259d
2659d
259
2659
25
269d
3
32
321
3215
325
3265
32659
32659d
3269d
326a9d
36a9d
376a9d
3269
369
3659
4
42
432
4321
43215
4325
43265
432659
43659
43769
4376a9
4376a9d
437659
4365
4376ad
47ad
476a9d
47a9d26a9d
437aed
47aed
487baed
4376aed36aed
26ad
26aed
37aed
26ae
326ae
36ae
376ae
37ae
437bae
47bae
487bae
159de
159e
159ae
15ae
37bae
156ae
16ae
126ae
487be
487bfe
437be
47be
437bfe
47bfe
37be
37bfe
48bfe
37bf
437bf
47bf
487bf
48bf
15aef
156aef
126aef
26aef
26af
26abf
26bf
48cbf
16aef
267bf47baed
437baed
376ad
376aed
326ad
36ad
326aed27bf
237bf
126af
126abf
16af
156af
16abf
156abf
48cf
48cgf
48cg156abfg
16abfg
126abfg
126bfg
26bfg
267bfg
237bfg
37bfg
37bg
37bcg
37cg
27bfg
378cg
1267bfg
38cg
348cg
237bg
237bcg
27bg
267bg
27bcg
267bcg
1267bg
1267bcg
16bfg
231234
12348
1238
12378
1278
12678c1267c
1267bc
167bcg
16bcg
16bg
13
123
1278c
12378c
234
2348
238
2378
2378c278c
27c
237c
237cg
2378cg
34
348
38
378c
38c
348c
48
48c
我的结果大概就这么多,这只是从底边进入的直线得到的。
统计情况:
统计以某字符开头的数量 即,从底边哪个格子进入 |
|
1 | 44 |
2 | 43 |
3 | 43 |
4 | 44 |
我大概用图测试了上面很多的结果,都是ok的,而且是没有重复的。
那我们推广到任意一条直线,结论就是:
一顿分析猛如虎,我也不知道答案对不对,但思路应该是没啥大问题的吧
代码:整个代码就是在计算每条直线上每个点所在的位置,记录整个直线经过的格子集合,以字符串的形式存放起来,最后统计结果。似乎没啥好看的
import java.util.HashSet;
import java.util.Set;
public class Main {
//方格字符标记
String[][] ss = { { "1", "2", "3", "4" }, { "5", "6", "7", "8" }, { "9", "a", "b", "c" }, { "d", "e", "f", "g" } };
//结果集合
Set set = new HashSet();
int a = 0, b = 0, c = 0, d = 0;
public Main() {
//遍历x1,x2
for (int x1 = 0; x1 <= 400; x1++) {
for (int x2 = 0; x2 <= 400; x2++) {
// System.out.println("x1="+x1+",x2="+x2);
if (x1 == 0 || x1 == 400) {
// 固定x1,直线从侧边出去的结果
getlist4(x1, x2);
}
// 固定y=400,直线从顶部出去的数量结果
getlist(x1, x2);
}
}
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
System.out.println(set.size());
}
// 分别统计字符开头的数据,用于观察
public void count(String s) {
if (s.startsWith("1")) {
a++;
} else if (s.startsWith("2")) {
b++;
} else if (s.startsWith("3")) {
c++;
} else if (s.startsWith("4")) {
d++;
}
}
// 求顶部结果
public void getlist(double x1, double x2) {
String s = "";
for (int i = 0; i < 400; i++) {
double x = x2 + (x1 - x2) / 400 * i;
if (x > 0 && x < 100) {// 第一格内
if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][0])) {
s += ss[i / 100][0];
}
} else if (x > 100 && x < 200) {// 第二格内
if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][1])) {
s += ss[i / 100][1];
}
} else if (x > 200 && x < 300) {// 第三格内
if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][2])) {
s += ss[i / 100][2];
}
} else if (x > 300 && x < 400) {// 第四格内
if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][3])) {
s += ss[i / 100][3];
}
}
}
// 存起来
if (!s.equals("") && !set.contains(s)) {
// System.out.println(s);
count(s);
set.add(s);
}
}
// 求两侧边结果
public void getlist4(double x1, double x2) {
String s = "";
// 这里x1,x2固定时,y在变化,
for (int j = 0; j < 400; j++) {
//每次变化都是不一样的直线
for (int i = 0; i < j; i++) {
double x = x2 + (x1 - x2) / j * i;
if (x > 0 && x < 100) {// 第一格内
if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][0])) {
s += ss[i / 100][0];
}
} else if (x > 100 && x < 200) {// 第二格内
if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][1])) {
s += ss[i / 100][1];
}
} else if (x > 200 && x < 300) {// 第三格内
if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][2])) {
s += ss[i / 100][2];
}
} else if (x > 300 && x < 400) {// 第四格内
if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][3])) {
s += ss[i / 100][3];
}
}
}
// 存起来
if (!s.equals("") && !set.contains(s)) {
// System.out.println(s);
count(s);
set.add(s);
}
s = "";
}
}
public static void main(String[] args) {
new Main();
}
}