/**
问题描述:
一个公司的所有员工正在风景秀丽的海南岛旅游,计划行程准备从三亚码头渡海去
蜈支洲岛,但由于最近的台风“琼花”摧毁了所有的渡船,游轮,轮船,帆船等,只
有一种正方形的木筏还在运营中。
这种木筏有N排座位,编号从1到N(N可能是一个两位数);每排有N列座位,编号为
(A, B, C, D ..), 这样每个座位都有唯一的对应号码,由一个数字和一个字母
组成,例如,“9C” 代表第9排第3个座位。但是有一些座位已经预先放上了空桶,
假设空桶没有分量,但该座位也不能再坐人了。另外还有一些座位已经分配给了
当地的渔民。为了航行安全,木筏渡海时必须保持平衡,所以必须满足以下条件:
(1) 前一半座位所坐的总人数要等于后一半座位所坐的总人数。
(2) 左一半座位所坐的总人数要等于右一半座位所坐的总人数。
现在,看如何来安排座位,使得木筏一次可以坐更多的公司员工。假设员工的数量
没有限制,并且每个人无论是员工还是渔民的重量都是相等的。
例如,有4*4的木筏,如下图所示:
A B C D
1 |. S S S
2 |S . . T
3 |. T . .
4 |. S . .
S是被空桶占着的座位,T是渔民的座位,.是空余的座位。
那么,最多还可以坐六名公司员工,保证前后左右分别都相等。
A B C D
1 |N S S S
2 |S N N T
3 |N T N .
4 |. S N .
N为我们的员工,左总人数=4=右总人数,前总人数=4=后总人数。
这样,总共最多可以安排6名员工,同时还能保证木筏平衡。
Write a function:
class Solution { public int solution(int N, String S, String T); }
给定木筏的大小N,和两个字符串分别代表桶的位置S和渔民的位置T,返回能
保障平衡的可容纳员工的最多人数。如果无论怎样也不能保障平衡,返回-1.
For instance,
given N=4, S="1B,1C,4B,1D,2A" and T="3B,2D",
your function should return 6.
Assume that:
(1) N is an even integer within the range [2..26];
(2) Strings S, T consist of valid seat numbers, separated with comma
and no whitespace chars;
(3) Each seat number can only appear no more than once in the strings;
(4) Any seat number cannot appear in both S and T at the same time.
*/
// you can use includes, for example:
// #include <algorithm>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <iostream>
#include <iosfwd>
using namespace std;
// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;
//
// -----------------
// | | |
// | 1,i | 2,j |
// | | |
// -----------------
// | | |
// | 3,m | 4,n |
// | | |
// -----------------
int solution(int N, char* S, char* T)
{
// write your code in C++14 (g++ 6.2.0)
char *wood_boat = new char[N*N];
memset(wood_boat, '.', N*N);
const int H = N/2; // 木筏子左上(1)右上(2)左下(3)右下(4)这四个象限的行数和列数
const int Q = H*H; // 每个象限的座位总数
const int LEN_S = strlen(S), LEN_T = strlen(T);
int S1 = 0, S2 = 0, S3 = 0, S4 = 0, /* 四个象限各自空桶的数量 */
T1 = 0, T2 = 0, T3 = 0, T4 = 0, /* 四个象限各自渔民的数量 */
E1 = 0, E2 = 0, E3 = 0, E4 = 0; /* 四个象限各自空位的数量(最重要的就是算出空位的数量) */
int i = 0, j = 0, m = 0, n = 0;
// Step-1: 计算每个象限中空桶的数量
while (i < LEN_S)
{
int x = 0, y = 0; // 任何一个空桶在木筏中的行列位置下标[0,N)
// 确保不越界,第一位必须是数字
assert(i < (LEN_S-1));
assert(S[i] >= '1' && S[i] <= '9');
if (S[i+1] >= '0' && S[i+1] <= '9') /* 当前行号是一个两位数,例如'10C' */
{
// 确保不越界,下一位必须是字母
assert(i < (LEN_S-2));
assert(S[i+2] >= 'A' && S[i+2] <= 'Z');
x = (S[i] - '0')*10 + S[i+1] - '1'; // 行号下标
y = S[i+2] - 'A'; // 列号下标
i += 4; // 此种情况步长为4
}
else /* 当前行号是个一位数 */
{
// 下一位必须是字母
assert(S[i+1] >= 'A' && S[i+1] <= 'Z');
x = S[i] - '1'; // 行号下标
y = S[i+1] - 'A'; // 列号下标
i += 3; // 此种情况步长为3
}
// 检查参数有效性和重复参数
if (x >= N || y >= N)
{
std::cout << "\nERROR: Seat NO. out-of-range in second argument ["
<< S << "](" << (x+1) << char('A'+y) << ")!\n";
return -1;
}
if (wood_boat[x*N+y] != '.')
{
std::cout << "\nERROR: Duplicate seat NO. in second argument ["
<< S << "](" << (x+1) << char('A'+y) << ")!\n";
return -1;
}
// 标记木筏中空桶的位置'S'
wood_boat[x*N+y] = 'S';
// 判断当前空桶位于哪个象限,并且分别计数
if (x < H && y < H) ++S1;
else if (x < H && y >= H) ++S2;
else if (x >= H && y < H) ++S3;
else /*(x >= H && y >= H)*/ ++S4;
}// end while
// Step-2: 计算每个象限中渔民的数量
i = 0;
while (i < LEN_T)
{
int x = 0, y = 0; // 任何一个渔民在木筏中的行列位置下标[0,N)
// 确保不越界,第一位必须是数字
assert(i < (LEN_T-1));
assert(T[i] >= '1' && T[i] <= '9');
if (T[i+1] >= '0' && T[i+1] <= '9') /* 当前行号是一个两位数,例如'10D' */
{
// 确保不越界,下一位必须是字母
assert(i < (LEN_T-2));
assert(T[i+2] >= 'A' && T[i+2] <= 'Z');
x = (T[i] - '0')*10 + T[i+1] - '1'; // 行号下标
y = T[i+2] - 'A'; // 列号下标
i += 4; // 此种情况步长为4
}
else /* 当前行号是个一位数 */
{
// 下一位必须是字母
assert(T[i+1] >= 'A' && T[i+1] <= 'Z');
x = T[i] - '1'; // 行号下标
y = T[i+1] - 'A'; // 列号下标
i += 3; // 此种情况步长为3
}
// 检查参数有效性和重复参数
if (x >= N || y >= N)
{
std::cout << "\nERROR: Seat NO. out-of-range in third argument ["
<< T << "](" << (x+1) << char('A'+y) << ")!\n";
return -1;
}
if (wood_boat[x*N+y] != '.')
{
std::cout << "\nERROR: Duplicate seat NO. in third argument ["
<< T << "](" << (x+1) << char('A'+y) << ")!\n";
return -1;
}
// 标记木筏中渔民的位置'T'
wood_boat[x*N+y] = 'T';
// 判断当前渔民位于哪个象限,并且分别计数
if (x < H && y < H) ++T1;
else if (x < H && y >= H) ++T2;
else if (x >= H && y < H) ++T3;
else /*(x >= H && y >= H)*/ ++T4;
}// end while
// Step-3: 算出四个象限空位的数量
E1 = Q - S1 - T1;
E2 = Q - S2 - T2;
E3 = Q - S3 - T3;
E4 = Q - S4 - T4;
// Step-4: 打印木筏的布局
std::cout << "\n ┌----┬----┐";
std::cout << "\n │ Q1 │ Q2 │";
std::cout << "\n ├----┼----┤";
std::cout << "\n │ Q3 │ Q4 │";
std::cout << "\n └----┴----┘\n";
std::cout << "\nIn this case, \n";
std::cout << "1th Quadrant(Q1): [S:" << S1 << ", T:" << T1 << ", E:" << E1 << "]\n";
std::cout << "2th Quadrant(Q2): [S:" << S2 << ", T:" << T2 << ", E:" << E2 << "]\n";
std::cout << "3rd Quadrant(Q3): [S:" << S3 << ", T:" << T3 << ", E:" << E3 << "]\n";
std::cout << "4th Quadrant(Q4): [S:" << S4 << ", T:" << T4 << ", E:" << E4 << "]\n";
// 打印木筏矩阵图像
printf("\n ");
for (i = 0; i < N; ++i)
printf("%c ", 'A'+i);
printf("\n");
for (i = 0; i < N; ++i)
{
printf("%2d[ ", i+1);
for (j = 0; j < N; ++j)
{
printf("%c ", wood_boat[i*N+j]);
}
printf("]\n");
}
printf("\n");
delete []wood_boat;
// Step-5: 判断平衡性并计算最大可坐员工的数量
// Note: 任何一个象限都有可能不坐一个员工就已经平衡了,但未必就没有解;
// 或者它的所有空位都坐满员工了才能平衡。所以应从0到Ei全部遍历。
// 在任何一个象限里,如果坐不满就能满足平衡要求了,那么人的具体
// 位置并不重要。所以,我们只需要知道每个象限最多能坐多少员工并且
// 还能够保持平衡即可。
int result = 0;
for (i = 0; i <= E1; ++i)
for (j = 0; j <= E2; ++j)
for (m = 0; m <= E3; ++m)
for (n = 0; n <= E4; ++n)
{
// 每个象限可坐人的数量(渔民和员工,空桶不计重量)
int C1 = i + T1, C2 = j + T2, C3 = m + T3, C4 = n + T4;
// 平衡否?
if (((C1+C2) == (C3+C4)) && ((C1+C3) == (C2+C4)))
{
// 当平衡时可坐的员工数为一个解
const int total = i + j + m + n;
// 平衡后排除全0组合(原有渔民已经平衡)(而不能一开始就排除全0组合)
if (total == 0) continue;
std::cout << "Found solution [Employe: " << total << "]! Layout: [Q1:" << i
<< "],[Q2:" << j << "],[Q3:" << m << "],[Q4:" << n << "]\n";
// 是否为最大解?
if (total > result)
{
std::cout << "*** (And this is a bigger result than " << result << ")\n";
result = total;
}
else
{
std::cout << "*** (Already got a same/bigger result: " << result << ")\n";
}
}// end if
}// end for
// Step-6: 是否有解?
if (result == 0)
return -1;
else
return result;
}
// please don't modify main function
// Input parameter format: "4 [1B,1C,4B,1D,2A] [3B,2D]"
int main( int argc, const char* argv[] )
{
if (argc != 4)
{
printf("\nDon't use whitespace or other special char in all arguments!\n\n");
return 1;
}
// 断言N是偶数,而且N的取值范围为[2,26],即可能为两位数
int N = atoi(argv[1]);
assert(N >=2 && N <= 26 && N == (N/2)*2);
int len = strlen(argv[2]);
assert(len >= 2);
char* str1 = new char[len-2+1];
strncpy(str1, argv[2]+1, len-2); // remove '[' and ']' from two sides
str1[len-2] = '\0'; // append '\0'
len = strlen(argv[3]);
assert(len >= 2);
char* str2 = new char[len-2+1];
strncpy(str2, argv[3]+1, len-2); // remove '[' and ']' from two sides
str2[len-2] = '\0'; // append '\0'
printf("\nAt last, Result: %d\n\n", solution(N, str1, str2));
delete []str2;
delete []str1;
return 0;
}