Problem 61
Cyclical figurate numbers
Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:
Triangle | P3,n=n(n+1)/2 | 1, 3, 6, 10, 15, … |
Square | P4,n=n2 | 1, 4, 9, 16, 25, … |
Pentagonal | P5,n=n(3n−1)/2 | 1, 5, 12, 22, 35, … |
Hexagonal | P6,n=n(2n−1) | 1, 6, 15, 28, 45, … |
Heptagonal | P7,n=n(5n−3)/2 | 1, 7, 18, 34, 55, … |
Octagonal | P8,n=n(3n−2) | 1, 8, 21, 40, 65, … |
The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three interesting properties.
- The set is cyclic, in that the last two digits of each number is the first two digits of the next number (including the last number with the first).
- Each polygonal type: triangle (P3,127=8128), square (P4,91=8281), and pentagonal (P5,44=2882), is represented by a different number in the set.
- This is the only set of 4-digit numbers with this property.
Find the sum of the only ordered set of six cyclic 4-digit numbers for which each polygonal type: triangle, square, pentagonal, hexagonal, heptagonal, and octagonal, is represented by a different number in the set.
循环的多边形数
三角形数、正方形数、五边形数、六边形数、七边形数和八边形数统称为多边形数。它们分别由如下的公式给出:
三角形数 | P3,n=n(n+1)/2 | 1, 3, 6, 10, 15, … |
正方形数 | P4,n=n2 | 1, 4, 9, 16, 25, … |
五边形数 | P5,n=n(3n−1)/2 | 1, 5, 12, 22, 35, … |
六边形数 | P6,n=n(2n−1) | 1, 6, 15, 28, 45, … |
七边形数 | P7,n=n(5n−3)/2 | 1, 7, 18, 34, 55, … |
八边形数 | P8,n=n(3n−2) | 1, 8, 21, 40, 65, … |
由三个4位数8128、2882、8281构成的有序集有如下三个有趣的性质。
- 这个集合是循环的,每个数的后两位是后一个数的前两位(最后一个数的后两位也是第一个数的前两位)。
- 每种多边形数——三角形数(P3,127=8128)、正方形数(P4,91=8281)和五边形数(P5,44=2882)——在其中各有一个代表。
- 这是唯一一个满足上述性质的4位数有序集。
存在唯一一个包含六个4位数的有序循环集,每种多边形数——三角形数、正方形数、五边形数、六边形数、七边形数和八边形数——在其中各有一个代表。求这个集合的元素和。
package projecteuler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import junit.framework.TestCase;
public class Prj61 extends TestCase {
public static int NUM_OF_SIZE = 6;
public void testCyclicalFigurateNumbers() {
DfsCyclicalFigurateNumbers2 dfsC2 = new DfsCyclicalFigurateNumbers2();
dfsC2.doTest();
/**
* 分层搜索,计算量太大,改为起始点固定,一步一步只要保持前一个最后两位和后一个量前两位相同即可.(只需保持一个使用类型标识,下次选取不同即可
* ,减小搜索深度和复杂度)
*/
// DfsCyclicalFigurateNumbers dfsC = new DfsCyclicalFigurateNumbers();
// dfsC.doTest();
}
public interface ICalculateDataList {
public List<Integer> getDataList(int start, int end);
}
public static class CyclicalFigurateNumbersTestCase2 {
public int n;
public int[] data;
public int[] idx;
public CyclicalFigurateNumbersTestCase2(int n) {
super();
this.n = n;
data = new int[n];
idx = new int[n];
}
public void setValue(int id, int val, int mapId) {
data[id] = val;
idx[id] = mapId;
}
public int[] getResult() {
return Arrays.copyOf(data, data.length);
}
public boolean isOutOfBoundary(int id) {
return id >= data.length;
}
public boolean isFind() {
int[] _front = splitInt(data[0]);
int[] _tail = splitInt(data[NUM_OF_SIZE - 1]);
return _front[0] == _tail[1];
}
public boolean isValidMap(int id, int mapId) {
for (int i = 0; i < id; i++) {
if (idx[i] == mapId) {
return false;
}
}
return true;
}
public boolean isValid(int id, int val) {
if (id == 0) {
return true;
}
int[] _front = splitInt(data[id - 1]);
int[] _tail = splitInt(val);
return _front[1] == _tail[0];
}
public void printResult() {
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + ",");
}
System.out.println();
for (int i = 0; i < idx.length; i++) {
System.out.print(idx[i] + ",");
}
System.out.println();
}
}
public static class DfsCyclicalFigurateNumbers2 {
public List<int[]> rsList = new ArrayList<int[]>();
public void doTest() {
ICalculateDataList Octagonal = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (3 * n - 2);
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Heptagonal = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (5 * n - 3) / 2;
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Hexagonal = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (2 * n - 1);
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Pentagonal = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (3 * n - 1) / 2;
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Square = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * n;
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Triangle = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (n + 1) / 2;
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
Map<Integer, List<Integer>> mapList = new HashMap<Integer, List<Integer>>();
mapList.put(0, Octagonal.getDataList(1000, 9999));
mapList.put(1, Heptagonal.getDataList(1000, 9999));
mapList.put(2, Hexagonal.getDataList(1000, 9999));
mapList.put(3, Pentagonal.getDataList(1000, 9999));
mapList.put(4, Square.getDataList(1000, 9999));
mapList.put(5, Triangle.getDataList(1000, 9999));
// mapList.put(0, Pentagonal.getDataList(1000, 9999));
// mapList.put(1, Square.getDataList(1000, 9999));
// mapList.put(2, Triangle.getDataList(1000, 9999));
CyclicalFigurateNumbersTestCase2 ts = new CyclicalFigurateNumbersTestCase2(
NUM_OF_SIZE);
dfs(0, ts, mapList, rsList);
System.out.println("result=_____________");
for (int i = 0; i < rsList.size(); i++) {
int[] rs = rsList.get(i);
for (int j = 0; j < rs.length; j++) {
System.out.print(rs[j] + ",");
}
System.out.println();
}
}
private void dfs(int startIndex, CyclicalFigurateNumbersTestCase2 ts,
Map<Integer, List<Integer>> mapList, List<int[]> rs) {
if (ts.isOutOfBoundary(startIndex)) {
if (ts.isFind()) {
rs.add(ts.getResult());
ts.printResult();
}
return;
}
if (startIndex == 0) {
List<Integer> primeList = mapList.get(startIndex);
for (int i = 0; i < primeList.size(); i++) {
int setVal = primeList.get(i);
if (ts.isValid(startIndex, setVal)) {
ts.setValue(startIndex, setVal, 0);
dfs(startIndex + 1, ts, mapList, rs);
}
}
} else {
for (Entry<Integer, List<Integer>> entry : mapList.entrySet()) {
if (!ts.isValidMap(startIndex, entry.getKey())) {
continue;
}
List<Integer> primeList = entry.getValue();
for (int i = 0; i < primeList.size(); i++) {
int setVal = primeList.get(i);
if (ts.isValid(startIndex, setVal)) {
ts.setValue(startIndex, setVal, entry.getKey());
dfs(startIndex + 1, ts, mapList, rs);
}
}
}
}
}
}
public static class CyclicalFigurateNumbersTestCase {
public int n;
public int[] data;
public CyclicalFigurateNumbersTestCase(int n) {
super();
this.n = n;
data = new int[n];
}
public void setValue(int id, int val) {
data[id] = val;
}
public int[] getResult() {
return Arrays.copyOf(data, data.length);
}
public boolean isOutOfBoundary(int id) {
return id >= data.length;
}
public boolean isFind() {
Combination cb = new Combination(data.length, 0);
List<int[]> allCbs = cb.generateCom();
for (int i = 0; i < allCbs.size(); i++) {
int[] arr = allCbs.get(i);
int[] tp = new int[arr.length];
for (int j = 0; j < arr.length; j++) {
tp[j] = data[arr[j]];
}
if (isCheckOK(tp)) {
return true;
}
}
return false;
}
private boolean isCheckOK(int[] tp) {
for (int i = 0; i < tp.length - 1; i++) {
int[] _front = splitInt(tp[i]);
int[] _tail = splitInt(tp[i + 1]);
if (_tail[0] != _front[1]) {
return false;
}
}
int[] _front = splitInt(tp[0]);
int[] _tail = splitInt(tp[tp.length - 1]);
return _front[0] == _tail[1];
}
public boolean isValid(int id, int val) {
return true;
}
public void printResult() {
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + ",");
}
System.out.println();
}
}
public static class DfsCyclicalFigurateNumbers {
public List<int[]> rsList = new ArrayList<int[]>();
public void doTest() {
ICalculateDataList Octagonal = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (3 * n - 2);
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Heptagonal = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (5 * n - 3) / 2;
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Hexagonal = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (2 * n - 1);
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Pentagonal = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (3 * n - 1) / 2;
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Square = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * n;
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
ICalculateDataList Triangle = new ICalculateDataList() {
@Override
public List<Integer> getDataList(int start, int end) {
List<Integer> dataList = new ArrayList<Integer>();
for (int n = 1;; n++) {
int val = n * (n + 1) / 2;
if (val >= start) {
if (val > end) {
break;
}
int[] _val = splitInt(val);
if (_val[0] >= 10 && _val[1] >= 10) {
dataList.add(val);
}
}
}
return dataList;
}
};
Map<Integer, List<Integer>> mapList = new HashMap<Integer, List<Integer>>();
mapList.put(0, Octagonal.getDataList(1000, 9999));
mapList.put(1, Heptagonal.getDataList(1000, 9999));
mapList.put(2, Hexagonal.getDataList(1000, 9999));
mapList.put(3, Pentagonal.getDataList(1000, 9999));
mapList.put(4, Square.getDataList(1000, 9999));
mapList.put(5, Triangle.getDataList(1000, 9999));
// mapList.put(0, Pentagonal.getDataList(1000, 9999));
// mapList.put(1, Square.getDataList(1000, 9999));
// mapList.put(2, Triangle.getDataList(1000, 9999));
CyclicalFigurateNumbersTestCase ts = new CyclicalFigurateNumbersTestCase(
NUM_OF_SIZE);
dfs(0, ts, mapList, rsList);
System.out.println("result=_____________");
for (int i = 0; i < rsList.size(); i++) {
int[] rs = rsList.get(i);
for (int j = 0; j < rs.length; j++) {
System.out.print(rs[j] + ",");
}
System.out.println();
}
}
private void dfs(int startIndex, CyclicalFigurateNumbersTestCase ts,
Map<Integer, List<Integer>> mapList, List<int[]> rs) {
if (ts.isOutOfBoundary(startIndex)) {
ts.printResult();
if (ts.isFind()) {
rs.add(ts.getResult());
ts.printResult();
}
return;
}
List<Integer> primeList = mapList.get(startIndex);
for (int i = 0; i < primeList.size(); i++) {
int setVal = primeList.get(i);
if (ts.isValid(startIndex, setVal)) {
ts.setValue(startIndex, setVal);
dfs(startIndex + 1, ts, mapList, rs);
}
}
}
}
public static int[] splitInt(int val) {
String str = Integer.toString(val);
return new int[] { Integer.parseInt(str.substring(0, 2)),
Integer.parseInt(str.substring(2, str.length())) };
}
public static class Combination {
private int[] startArr;
public Combination(int size) {
this(size, 1);
}
public Combination(int size, int startNum) {
startArr = new int[size];
for (int i = 0; i < size; i++) {
startArr[i] = i + startNum;
}
}
public List<int[]> generateCom() {
List<int[]> ret = new ArrayList<int[]>();
ret.add(Arrays.copyOf(startArr, startArr.length));
while (true) {
int lastAsc = findLastAsc(startArr);
if (lastAsc == -1) {
break;
}
int lasBigThanAsc = findBigThanAsc(startArr, lastAsc);
exchangeEach(lastAsc, lasBigThanAsc, startArr);
ret.add(Arrays.copyOf(startArr, startArr.length));
}
return ret;
}
private int findBigThanAsc(int[] startArr2, int lastAsc) {
int i = 0;
for (i = startArr2.length - 1; i > lastAsc; i--) {
if (startArr2[i] > startArr2[lastAsc]) {
return i;
}
}
assert (i > lastAsc);
return i;
}
private void exchangeEach(int lastAsc, int lasBigThanAsc,
int[] startArr2) {
int temp = startArr2[lastAsc];
startArr2[lastAsc] = startArr2[lasBigThanAsc];
startArr2[lasBigThanAsc] = temp;
int[] sortArr = getCopyArr(lastAsc + 1, startArr2);
for (int i = 0; i < sortArr.length / 2; i++) {
temp = sortArr[sortArr.length - 1 - i];
sortArr[sortArr.length - 1 - i] = sortArr[i];
sortArr[i] = temp;
}
for (int i = lastAsc + 1; i < startArr2.length; i++) {
startArr2[i] = sortArr[i - lastAsc - 1];
}
}
private int[] getCopyArr(int start, int[] startArr2) {
int[] ret = new int[startArr2.length - start];
for (int i = start; i < startArr2.length; i++) {
ret[i - start] = startArr2[i];
}
return ret;
}
private int findLastAsc(int[] startArr2) {
for (int i = startArr2.length - 1; i > 0; i--) {
if (startArr2[i] > startArr2[i - 1]) {
return i - 1;
}
}
return -1;
}
public long getIntVal(int[] arr) {
long sum = arr[0];
for (int i = 1; i < arr.length; i++) {
sum = sum * 10 + arr[i];
}
return sum;
}
}
}