1.中国象棋
题目描述:在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好有一个棋子。
输入:
一行包含两个整数N,M,之间由一个空格隔开。
输出:
总共的方案数,由于该值可能很大,只需给出方案数mod 9999973的结果。
样例输入:
1 3
样例输出:
7
说明/提示
样例说明
除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。
数据范围
100%的数据中N和M均不超过100
50%的数据中N和M至少有一个数不超过8
30%的数据中N和M均不超过6
分析过程:
首先考虑合法的状态,即每一行每一列的炮的数量≤2,所以考虑用一个数组存储有几列放了一个炮,有几列放了两个炮。因此定义状态数组代表在前i行,有j列放了1个棋子,有k列放了2个棋子的合法方案数。这个时候知道了全部的列数,以及知道部分情况的列数,因此可以求出不放棋子的列数,即空的=全部-合法的,也就是空的列数=m-j-k。因此我们可以确定:
- 可以在当前第i行不放棋子
- 可以在当前第i行放1个棋子
- 可以在当前第i行放2个棋子
然后分析上述三种情况:
- 不放棋子,则直接继承上面的状态,也就是
- 放1个棋子:显然我们不会选择将棋子放在已经有两个棋子的列上。因此存在两种情况:
- 1. 将棋子放在原来只有1个棋子的列上:
- 2. 将棋子放在原来没有棋子的列上:
- 1. 将棋子放在原来只有1个棋子的列上:
这里需要解释这两种情况:
1. 放在原来只有1个棋子的列:我们在某一个有一个棋子的列放置棋子,会使这一列变成有两个棋子,即要得到需要在j+1个有一个棋子的列上放置棋子,然后变成j个有一个棋子的列,同时又会得到一个新的有两个棋子的列,因此在此之前必须有k-1个放置2个棋子的列。所以
的状态传递给
存在(j+1)种情况,即可以在(j+1)列中的任意一列放置1个棋子。
2. 放在原来没有棋子的列:我们在一个没有棋子的列放置棋子,会得到一个新的有1个棋子的列。即要从j-1得到j,而这个过程中放置有2个棋子得列的数量是不会变的,所以从k传递即可,即的状态可以传递给
。因为存在有
个空列,所以要乘以
。
- 放2个棋子:这个时候存在3种放法:
- 1. 将其中1个棋子放在原来只有1个棋子的列,另一个棋子放在原来没有棋子的列:
- 2. 都放在原来没有棋子的列:
- 3. 都放在原来只有1个棋子的列:
- 1. 将其中1个棋子放在原来只有1个棋子的列,另一个棋子放在原来没有棋子的列:
这里需要解释这三种情况:
1. 将其中1个棋子放在原来存在1个棋子的列,另一个放在原来不存在棋子的列。这个时候,我们放置之后,状态就变成了:一个没有棋子的列会变成一个存有1个棋子的列,另一个原本存有1个棋子的列变成了存有2个棋子的列。此时我们发现存在1个棋子的列的数量不会变,即第二维依然是j,又因为我们新增了一个存有2个棋子的列,所以需要从k-1转移过来,同时又因为我们可以在原来存有1个棋子的列中任意选择,而且空的列也可以任意放,所以需要
2. 都放在原来没有棋子的列。放置之后,会新增两个存有1个棋子的列,因此需要从j-2转移过来,而原来存有2个棋子的列的数量不变,仍然是k个。同时,因为在空的列中可以任意放置,根据排列组合公式,有种情况。
3. 都放在原来存有1个棋子的列。放置之后,这两个原本存有1个棋子的列就变成了两个存有2个棋子的列。即从j+2变成了j,从k-2变成了k。而且这两个棋子可以在任意原本存有1个棋子的列中任意选择,根据排列组合公式,有种情况。
最后需要注意的就是在遍历过程中的边界判断。
算法实现:
import java.util.Scanner;
public class Chess {
public static int f[][][] = new int[101][101][101];
public static int MOD = 9999973;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 行数
int M = sc.nextInt(); // 列数
int res = getResult(N, M);
System.out.println(res);
}
private static int getResult(int n, int m) {
f[0][0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
for (int k = 0; j + k <= m; k++) {
f[i][j][k] = f[i - 1][j][k];
if (k >= 1) {
f[i][j][k] += f[i - 1][j + 1][k - 1] * (j + 1);
}
if (j >= 1) {
f[i][j][k] += f[i - 1][j - 1][k] * (m - j - k + 1);
}
if (k >= 2) {
f[i][j][k] += f[i - 1][j + 2][k - 2] * MathC(j + 2);
}
if (k >= 1) {
f[i][j][k] += f[i - 1][j][k - 1] * j * (m - j - k + 1);
}
if (j >= 2) {
f[i][j][k] += f[i - 1][j - 2][k] * MathC(m - j - k + 2);
}
f[i][j][k] %= MOD;
}
}
}
int res = 0;
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= m; j++) {
res += f[n][i][j];
}
}
return res;
}
private static int MathC(int i) {
return ((i * (i - 1)) / 2) % MOD;
}
}
2.路灯
题目描述:妞妞有一天工作到很晚,回家的时候要穿过一条长l的笔直的街道,这条街道上有n个路灯。假设这条街起点为0,终点为l,第i个路灯坐标为ai。路灯发光能力以正数d来衡量,其中d表示路灯能够照亮的街道上的点与路灯的最远距离,所有路灯发光能力相同。为了让妞妞看清回家的路,路灯必须照亮整条街道,又为了节省电力希望找到最小的d是多少?
输入:
输入两行数据,第一行是两个整数:路灯数目n (1≤n≤1000),街道长度l (1 ≤l≤10^9)。第二行有n个整数ai (0 ≤ ai≤ l),表示路灯坐标,多个路灯可以在同一个点,也可以安放在终点位置。
输出:
输出能够照亮整个街道的最小d,保留两位小数。
样例输入:
7 15
15 5 3 7 9 14 0
样例输出:
2.50
分析过程:
找出相邻坐标差值中最大的,然后除以2就是最小的d。具体步骤如下:
- 输入路灯数目n、街道长度l;
- 输入路灯位置ai;
- 计算相邻路灯之间的距离S1,S2...
- 由于路灯发光能力相同,按照相邻路灯灯光刚好连接,最短发光距离应该是d=Si/2;
- 由于发光能力相同,而Si各不相同,为了满足照亮整个街道(灯光至少刚好连接)的条件,因此选取最大的Si*0.50;
算法实现:
import java.util.Arrays;
import java.util.Scanner;
public class StreetLamp {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String n_l = sc.nextLine();
String[] strNL = n_l.split(" ");
int n = Integer.parseInt(strNL[0]);
int l = Integer.parseInt(strNL[1]);
if ((n >= 1 && n <= 1000) && (l >= 1 && l <= Math.pow(10, 9))) {
String temp = sc.nextLine();
if (!temp.isEmpty()) {
String[] strNum = temp.split(" ");
int len = strNum.length;
if (len == n) {
int[] ai = new int[len];
for (int i = 0; i < len; i++) {
int aiTemp = Integer.parseInt(strNum[i]);
if (aiTemp < 0 || aiTemp > l) {
break;
}
ai[i] = aiTemp;
}
String res = getResult(ai, n, l);
System.out.println(res);
}
}
}
}
private static String getResult(int[] ai, int n, int l) {
Arrays.sort(ai);
for (int i = 0; i < n; i++) {
System.out.println(ai[i]);
}
double res = 0.00;
int i = 1;
while (i <= n - 1) {
double x = (ai[i] - ai[i - 1]) * 0.50;
if (x > res) {
res = x;
}
i++;
}
if (ai[0] - 0 > res) {
res = ai[0] - 0;
}
if (l - ai[n - 1] > res) {
res = l - ai[n - 1];
}
return String.format("%.2f", res);
}
}