5、实验四多边形游戏
实验内容
按照要求输入多边形的边和顶点,游戏第一步: 删除一条边, 随后的n-1步按以下方式操作:
1)选择一条边E以及由E连接着的2个顶点v1和v2
2)用一个新的顶点取代边E以及由E连着的2个顶点v1和v2。将由顶点v1和v2的整数值通过边E上的运算得到的结果赋予新顶点。直到最后,所有边被删除,确认使结果达到最大值的删除方式和最大值。
解题思路
通过所给的多边形,从顶点i(1<=i<=n)开始,长度为j(链中有j个顶点)的顺时针链p(i,j)可表示为v[i],op[i+1],…,v[i+j-1],如果这条链的最后一次合并运算在op[i+s]处发生(1<=s<=j-1),则可在op[i+s]处将链分割为两个子链p(i,s)和p(i+s,j-s)。若最优合并在op[i+s]处将p(i,j)分为两个长度小于j的子链的最大值和最小值均可计算出。
源代码
package d多边形游戏;
import java.util.HashMap;
import java.util.Scanner;
public class PolygonGame {
public static void main(String[] args) {
System.out.println("请输入边(点)的个数:");
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
long[][][] m = new long[n + 1][n + 1][2];
char[] op = new char[n + 1];
int[] v = new int[n + 1];
System.out.print("\n");
System.out.println("请输入边和点:");
for (int i = 1; i <= n; i++) { // i从1开始
op[i] = scanner.next().charAt(0);
v[i] = scanner.nextInt();
}
PolygonGame ploygonAgent = new PolygonGame(n, m, op, v);
for (int i = 1; i <= n; i++) { // 初始化m[i][j][0]和m[i][j][1]的第一列
m[i][1][0] = m[i][1][1] = v[i];
}
//执行函数
ploygonAgent.polyMax();
}
private int n; // 多边形边数
private char[] op; // 每条边的对应的操作(从1开始计数)
private long[][][] m; // m[i][n][1]:代表一开始删除第i条边,长度为n的链(包含n个顶点),所能得到的最大值
// m[i][n][0]:代表一开始删除第i条边,长度为n的链,所能得到的最小值
private int[][][] cut; // cut[i][j][0];表示m[i][j][0]这条链的达到最小数值的时候断开的位置
// cut[i][j][1]: 表示m[i][j][1]这条链的达到最大数值的时候断开的位置
private int firstDelEdge; // 记录最优情况下,第1条删除的边
private long bestScore; // 记录最优得分
// 初始化
public PolygonGame(int n, long[][][] m, char[] op, int[] v) {
this.n = n;
this.m = m;
this.op = op;
this.cut = new int[n + 1][n + 1][2];
}
private HashMap<String, Long> minMax(int i, int s, int j, HashMap<String, Long> resMap) {
int r = (i + s - 1) % n + 1;
long a = m[i][s][0], b = m[i][s][1], c = m[r][j - s][0], d = m[r][j - s][1];
if (op[r] == '+') {
resMap.put("minf", a + c);
resMap.put("maxf", b + d);
} else {
long[] e = new long[] { 0, a * c, a * d, b * c, b * d };
long minf = e[1], maxf = e[1];
for (int k = 2; k < 5; k++) {
if (minf > e[k])
minf = e[k];
if (maxf < e[k])
maxf = e[k];
}
resMap.put("minf", minf);
resMap.put("maxf", maxf);
}
return resMap;
}
/**
* @see 把断点填入cut[i][j][0]和cut[i][j][1],并把最值并把最值填入m[i][j][0] 和 m[i][j][1]
*/
private void polyMax() {
// 1 填表 m[i][j][0] 和 m[i][j][1] 和 cut[i][j][0] 和 cut[i][j][1]
HashMap<String, Long> resMap = new HashMap<>();
for (int j = 2; j <= n; j++) { // 链的长度
for (int i = 1; i <= n; i++) { // 一开始断开第i条边的时候
m[i][j][0] = Long.MAX_VALUE;
m[i][j][1] = Long.MIN_VALUE;
for (int s = 1; s < j; s++) { // 断开的位置
resMap = this.minMax(i, s, j, resMap);
if (m[i][j][0] > resMap.get("minf")) {
m[i][j][0] = resMap.get("minf");
cut[i][j][0] = s; // 记录该链取得最小值的断点
}
if (m[i][j][1] < resMap.get("maxf")) {
m[i][j][1] = resMap.get("maxf");
cut[i][j][1] = s; // 记录该链取得最大值的断点
}
}
}
}
// 2 根据表m算出第一次断开哪里的时候的数值最大,并输出一些相关数据
bestScore = m[1][n][1];
firstDelEdge = 1; // 一开始断开的边,初始化为第一条边
for (int i = 2; i <= n; i++) {
if (bestScore < m[i][n][1]) {
bestScore = m[i][n][1];
firstDelEdge = i; // 如果一开始断开第i边有更优的结果,则更新
}
}
// 3输出m矩阵的最小值和最大值
System.out.println();
System.out.println("最小值" + "\\" + "最大值");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
System.out.print(m[i][j][0] + "\\" + m[i][j][1] + "\t");
}
System.out.println();
}
// 4输出s矩阵的最大值位置
System.out.println();
System.out.println("给出最大值位置");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
System.out.print(cut[i][j][1] + "\t");
}
System.out.println();
}
System.out.print("\n");
System.out.println("多边形游戏首次删除第" + firstDelEdge + "次条边,结果为:" + bestScore);
}
}