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個棋子的列:我們在某一個有一個棋子的列放置棋子,會使這一列變成有兩個棋子,即要得到需要在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個棋子的列變成了存有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);
}
}