UVa1587 盒子
前言
第一次刷题,ac的感觉真的很棒!
题目
大意是说,输入6个面,判断是否是个长方体。
思路
根据长方体的特质来判断,比如说6个面中3个面是相互对应的,只有3条不同的边等等。
我就知道我肯定会卡在输入输出这上面一次的😂。
给大家看看我的ac...
实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
/**
* 习题3-10 盒子
* 判断是否是长方形,用6个面,其实就是3个面
*/
struct Panel {
int width;
int height;
}panels[6];
int lines[12];
// 判断是否面之间的长和宽是否相等
int isPanelsEquality(struct Panel panel1, struct Panel panel2) {
if ((panel1.width == panel2.width && panel1.height == panel2.height) ||
(panel1.width == panel2.height && panel1.height == panel2.width)) {
return 1;
}
return 0;
}
// 对边长进行排序
int* Bublesort(int a[],int n)
{
/* 气泡法要排序n次*/
for(int j = 0; j < n - 1; j++) {
for(int i = 0; i < n-j-1; i++) {
if(a[i] > a[i+1]) {
int k = a[i];
a[i] = a[i+1];
a[i+1] = k;
}
}
}
return a;
}
void caculate15() {
int w, h;
while (scanf("%d%d", &w, &h) != EOF) {
panels[0].width = w;
panels[0].height = h;
lines[0] = w;
lines[1] = h;
for (int i = 1; i < 6; i++) {
scanf("%d%d", &w, &h);
panels[i].width = w;
panels[i].height = h;
lines[i*2] = w;
lines[i*2+1] = h;
}
int hash[6];
int visited[6];
memset(hash, 0, sizeof(hash));
memset(visited, 0, sizeof(visited));
// 面是两两相等
for (int i = 0; i < 6; i++) {
if (visited[i] == 1) {
continue;
}
visited[i] = 1;
hash[i]++;
for (int j = 0; j < 6; j++) {
if (visited[j] != 0 || i == j) {
continue;
}
if (isPanelsEquality(panels[i], panels[j])) {
visited[j] = 1;
hash[i]++;
break;
}
}
}
// hash中的个数必然是0或者2
int result = 1;
for (int i = 0; i < 6; i++) {
if (visited[i] == 0 || (hash[i] != 2 && hash[i] != 0)) {
result = 0;
break;
}
}
if (result) {
// hash中存在3个2,表示面两两对应
int twocnt = 0;
for (int i = 0; i < 6; i++) {
if (hash[i] == 2) {
twocnt++;
}
}
if (twocnt != 3) {
result = 0;
} else {
result = 1;
}
if (result) {
// 还有面和面之间是有联系的,一个面和另外一个面是通过一条线联系,也就是说一共有4条相等的直线
// 统计12条直线里是否有4条相等的直线
int* line_hash = Bublesort(lines, 12);
if (line_hash[0] != line_hash[3] || line_hash[4] != line_hash[7] || line_hash[8] != line_hash[11]) {
result = 0;
}
}
}
if (result) {
printf("POSSIBLE\n");
}
else {
printf("IMPOSSIBLE\n");
}
}
}
int main() {
caculate15();
return 0;
}
思路已经说的很清楚了,纯c写代码真的很烦,明明c++11可以写得更快的。下面这个方法也是用纯c写的,来自台湾同胞~
void caculate16() {
int w, h, pallet[6][2] = {};
// 第一个面
while (scanf("%d%d", &w, &h) != EOF) {
if (w < h)
pallet[0][0] = w, pallet[0][1] = h;
else
pallet[0][0] = h, pallet[0][1] = w;
// 剩余的面
int i;
for (i = 1; i < 6; i++) {
scanf("%d%d", &w, &h);
if (w < h)
pallet[i][0] = w, pallet[i][1] = h;
else
pallet[i][0] = h, pallet[i][1] = w;
}
int used[6] = {}, ok = 1;
memset(used, 0, sizeof(used));
int side[3][2], count = 0; //3个不同的面
memset(side, 0, sizeof(side));
// side保存下来三个面的2条边
for (i = 0; i < 6; i++) {
if (used[i])
continue;
for (int j = i + 1; j < 6; j++)
if (!used[j] && pallet[i][0] == pallet[j][0] && pallet[i][1] == pallet[j][1]) {
used[i] = used[j] = 1;
break;
}
if (!used[i])
break;
side[count][0] = pallet[i][0];
side[count][1] = pallet[i][1];
count++;
}
// 不存在没有访问过的面
for (i = 0; i < 6; i++)
if (!used[i])
ok = 0;
if (ok) {
ok = 0;
//用那 3 塊去拚看看矩形的 上方一片、側邊兩片
for (i = 0; i <= 1; i++) {
for (int j = 0; j <= 1; j++) {
// 在这里先进行假定第一个面和第二个面相等(因为两个面之间必然存在相等的边)
if (side[0][i] == side[1][j]) {
// 同样的情况
if (side[0][!i] == side[2][0] && side[2][1] == side[1][!j])
ok = 1;
else if (side[0][!i] == side[2][1] && side[2][0] == side[1][!j])
ok = 1;
}
}
}
}
puts(ok ? "POSSIBLE" : "IMPOSSIBLE");
}
}
好吧,我要开始用c++11开始写了,既方便由可以学习c++11。
![](https://i.loli.net/2018/11/17/5beff4d639cbb.jpg)
关注公众号:数据结构与算法那些事儿,每天一篇数据结构与算法