uva-1587-Box

这道题写了大约2小时。一遍AC的时候还是非常开心,因为自己的解决办法不是很高明导致代码非常长。一方面说明思维缜密值得高兴,但这只能看作是我在歪路上策马奔腾最后也勉强过了而已。在解决问题前一定要对问题进行高度抽象,就目前而言还是不宜凭第一感觉去写,因为第一感觉往往是用牺牲了的代码简洁度换取思考上的快捷。俗称懒得动脑。这样是不行的,以后写题要对题目进行高度抽象,抓住重点,每写完一道题都要看题解,同时把相关代码和感悟放到这里。以下是本次的代码对比:

我的巨长无比的分类讨论代码:

#include
#include
int isame(int *a, int *b) {
if (a[0] == b[0] && a[1] == b[1])
return 1;
else return 0;
}
int main() {
int all[12] = { 0 };
while (scanf("%d", all) != EOF) {
int err = 0;
for (int i = 1; i <= 11; i++) scanf("%d", all + i);
for (int i = 0; i <= 11; i++) if (all[i] <= 0) err = 1;
if (err) { printf("IMPOSSIBLE\n"); continue; }
for (int i = 0; i <= 8; i = i + 2) {//过滤重复板
int mul = all[i] * all[i + 1];
int sum = all[i] + all[i + 1];
for (int j = i + 2; j <= 10; j = j + 2) {
if ((mul == all[j] * all[j + 1]) && (sum == all[j] + all[j + 1])) {
all[j] = 0;
all[j + 1] = 0;
break;//一块板只能删除对面的板
}
}
}
int count = 0;
for (int i = 0; i <= 11; i++) if (all[i]) count++;
if (count != 6) { printf("IMPOSSIBLE\n"); continue; }//木板不是3种
int board[3][2];
for (int i = 0, x = 0; i <= 10; i = i + 2) {
if (all[i] != 0) {
int y = 0;
board[x][y++] = all[i];
board[x++][y] = all[i + 1];
}
}//存入3块板数据
//接下来检查3个板是不是由3种数据构成,小于等于3种都可能构成立方体
//上一条作废,此时直接开始判断板是否能对齐即可
//上一条作废,还是应该判断有几种边
int num[6] = { 0 };
for (int i = 0, j = 0; i <= 2; i++) { num[j++] = board[i][0]; num[j++] = board[i][1]; }
int kind = 0;
for (int i = 0; i <= 5; i++)
for (int j = i + 1; j <= 5; j++)
if (num[i] == num[j]) num[j] = 0;
for (int i = 0; i <= 5; i++) if (num[i] != 0) kind++;
if (kind == 1) { printf("POSSIBLE\n"); continue; }
if (kind == 2) {
for (int i = 0; i <= 2; i++)
if (board[i][0] < board[i][1]) { int te = board[i][0]; board[i][0] = board[i][1]; board[i][1] = te; }
//完成降序排列,方便判断板是否相同
if (isame(board[0], board[1]) && isame(board[1], board[2])) { printf("IMPOSSIBLE\n"); continue; }
if (!isame(board[0], board[1]) && !isame(board[1], board[2]) && !isame(board[0], board[2])) { printf("IMPOSSIBLE\n"); continue; }
int i, j;
for (i = 0; i <= 2; i++) {//此处向下3板中有2同
int sgg = 0;
for (j = i + 1; j <= 2; j++) {
if (isame(board[i], board[j])) { sgg = 1; break; }
}
if (sgg) break;
}
if (board[i][0] == board[i][1]) { printf("IMPOSSIBLE\n"); continue; }
printf("POSSIBLE\n");
}
if (kind == 3) {
int errr = 0;
for (int i = 0; i <= 2; i++)
if (board[i][0] == board[i][1]) errr = 1;
if (errr) { printf("IMPOSSIBLE\n"); continue; }
/*int i, j;
for (i = 0; i <= 2; i++) {
int errrr = 0;
for (j = i+1; j <= 2; j++) {
if (board[i][0] == board[j][0]) { errrr = 1; break; }
}
if (errrr) break;
}//找到可以连接的board[i]和board[j]*///这里做点说明,已知板有三种数据,每块板由有2种数据构成,这3块板必定可以构成立方体
printf("POSSIBLE\n");
}
if (kind > 3) printf("IMPOSSIBLE\n");
}
return 0;

}

可以看到,分类讨论思维简单,但是代码巨长,而且其中好多代码实现的功能与要求相去甚远,十分不提倡。

以下是我目前认为很好的AC代码:

#include
#include
using namespace std;


int main() {
while (true) {
long int a[10][5] = { 0 };
for (int i = 0; i < 6; i++) {
if (scanf("%d", &a[i][0]) == EOF) return 0;
scanf("%d", &a[i][1]);
if (a[i][0] > a[i][1]) swap(a[i][0], a[i][1]);
}
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6 - i; j++) {
if (a[i][0] > a[i + j][0] || (a[i][0] == a[i + j][0] && a[i][1] > a[i + j][1])) {
swap(a[i][0], a[i + j][0]);
swap(a[i][1], a[i + j][1]);
}
}
}
if (a[0][0] == a[1][0] && a[1][0] == a[2][0] && a[2][0] == a[3][0] && a[0][1] == a[1][1] && a[1][1] == a[4][0] && a[4][0] == a[5][0] && a[2][1] == a[3][1] && a[3][1] == a[4][1] && a[4][1] == a[5][1])
printf("POSSIBLE\n");
else
printf("IMPOSSIBLE\n");
}

return 0;

可以看到,问题的关键在于板的拼接处边长相等,因此先排序后判断是否可以拼接代码效率非常高。

你可能感兴趣的:(算法竞赛入门经典,粉书)