問題
連接棋子
N個棋子放到了x軸座標1, 2, ..., n上。N是偶數。
其中n/2個是黑色棋子,剩下的n/2個是白色棋子。連接一個黑色棋子和白色棋子弄成一雙時,會有n/2個雙。連接一雙棋子時,會從左邊的棋子開始出發垂直往上走,然後水平往右走,接着重新垂直往下走,開拓到達右邊棋子的路。
長成這樣的 n個路不能相互重疊,也不能相互交叉。爲了能讓所有路的距離之和弄成最小,請編寫開拓n個路的程序。 這裏,距離的單位中垂直和水平都是1。
圖片1的情況,可以用其他方法連接,但是上面的連接方法是最小的連接方法,距離的值爲31。圖片2的情況,也有其他的方法,但是上面的方法是最小的連接方法,距離的值爲40。
限制時間 : 1.5秒
輸入
第一行給出表示點的個數的自然數n。n 是 400 以下的偶數。從下一行給出以n/2個0和 n/2個1構成的字符串。0是白色棋子, 1是黑色棋子。從左邊開始按順序與座標1,2, ... , n相應。
輸出
第一行輸出,路的距離之和中的最小值。
案例輸入1
10
1110100010
案例輸出1
31
案例輸入2
12
111000111000
案例輸出2
40
#include <stdio.h>
#include <algorithm>
using namespace std;
int n;
char ch[405];
int D[405][405], H[405][405];
int main(){
scanf("%d", &n);
scanf("%s", ch + 1);
for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)D[i][j] = H[i][j] = 1000000;
for (int i = 1; i <= n; i++)D[i][i - 1] = H[i][i - 1] = 0;
for (int i = 1; i <= n - 1; i++){
if (ch[i] == ch[i + 1])continue;
D[i][i + 1] = 3;
H[i][i + 1] = 1;
}
for (int i = 3; i<n; i += 2){
for (int j = 1; j + i <= n; j++){
for (int k = j; k<j + i; k += 2){
//k -- j+i
if (D[j][k - 1] != -1 && D[k + 1][j + i - 1] != -1 && ch[k] != ch[j + i]){
D[j][j + i] = min(D[j][j + i], D[j][k - 1] + D[k + 1][j + i - 1] + H[k + 1][j + i - 1] * 2 + 2 + (j + i - k));
H[j][j + i] = min(H[j][j + i], max(H[j][k - 1], H[k + 1][j + i - 1] + 1));
}
}
}
}
printf("%d\n", D[1][n]);
return 0;
}