问题
连接棋子
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;
}