version 1(20ms):
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 10;
int n,m,c,H[maxn][maxn],V[maxn][maxn];
char readchar(){
for(;;){
c = getchar();
if(c != '\n' && c != '\r') return c;
}
}
int countsq(int len){
int cnt = 0;
for(int i = 1;i+len <= n;i++){
for(int j = 1;j+len <= n;j++){
int mark = 1;
for(int k = 0;mark && k <= len - 1;k++){
if(!H[i][j+k] || !V[i+k][j]) mark = 0;//从左上角的点分别往右边和下边看
if(!H[i+len][j+k]) mark = 0;//从左下角的点往右边看
if(!V[i+k][j+len]) mark = 0;//从右上角的点往下边看
}
if(mark) cnt++;
}
}
return cnt;
}
int main(){
int kase = 0;
while(scanf("%d%d",&n,&m) == 2){
memset(H,0,sizeof(H));
memset(V,0,sizeof(V));
int a,b;
while(m--){
c = readchar();
scanf("%d %d",&a,&b);
if(c == 'H') H[a][b]= 1;
if(c == 'V') V[b][a]= 1;//这个地方注意书上说的是不对的 是 b a
}
if(++kase > 1) printf("\n**********************************\n\n");
printf("Problem #%d\n\n",kase);
int mark = 0;
for(int i = 1;i <= n;i++){
a = countsq(i);
if(a){
mark = 1;
printf("%d square (s) of size %d\n",a,i);
}
}
if(!mark) printf("No completed squares can be found.\n");
}
return 0;
}
又想了下,如果以某点为左上顶点不存在较短的正方形,那么也应该不存在更大的正方形,所以可以把这些点存储一下,以后根本不用去检查。
version 2:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 10;
int n,m,c,H[maxn][maxn],V[maxn][maxn],record[maxn][maxn];
char readchar(){
for(;;){
c = getchar();
if(c != '\n' && c != '\r') return c;
}
}
int countsq(int len){
int cnt = 0;
for(int i = 1;i+len <= n;i++){
for(int j = 1;j+len <= n;j++){
if(record[i][j]) continue;
int mark = 1;
for(int k = 0;mark && k <= len - 1;k++){
if(!H[i][j+k] || !V[i+k][j]) mark = 0;//从左上角的点分别往右边和下边看
if(!H[i+len][j+k]) mark = 0;//从左下角的点往右边看
if(!V[i+k][j+len]) mark = 0;//从右上角的点往下边看
}
if(mark) cnt++;
else record[i][j] = 1;
}
}
return cnt;
}
int main(){
int kase = 0;
while(scanf("%d%d",&n,&m) == 2){
memset(H,0,sizeof(H));
memset(V,0,sizeof(V));
memset(record,0,sizeof(record));
int a,b;
while(m--){
c = readchar();
scanf("%d %d",&a,&b);
if(c == 'H') H[a][b]= 1;
if(c == 'V') V[b][a]= 1;
}
if(++kase > 1) printf("\n**********************************\n\n");
printf("Problem #%d\n\n",kase);
int mark = 0;
for(int i = 1;i <= n;i++){
a = countsq(i);
if(a){
mark = 1;
printf("%d square (s) of size %d\n",a,i);
}
}
if(!mark) printf("No completed squares can be found.\n");
}
return 0;
}
但是 WA 了。。。仔细一想其实不对,如下图:
虽然这个点不存在边长为1的正方形,但是有边长为2的正方形,所以上面减少时间复杂度的做法行不通。但是如果这点的右边和下边这条线断掉的话,肯定不存在更大的正方形,以后是不需要检查的。
version 3(30ms):
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 10;
int n,m,c,H[maxn][maxn],V[maxn][maxn],record[maxn][maxn];
char readchar(){
for(;;){
c = getchar();
if(c != '\n' && c != '\r') return c;
}
}
int countsq(int len){
int cnt = 0;
for(int i = 1;i+len <= n;i++){
for(int j = 1;j+len <= n;j++){
if(record[i][j]) continue;
int mark = 1,mark2 = 0;
for(int k = 0;mark && k <= len - 1;k++){
if(!H[i][j+k] || !V[i+k][j]) {mark = 0,mark2 = 1;}//从左上角的点分别往右边和下边看
if(!H[i+len][j+k]) mark = 0;//从左下角的点往右边看
if(!V[i+k][j+len]) mark = 0;//从右上角的点往下边看
}
if(mark) cnt++;
if(mark2) record[i][j] = 1;
}
}
return cnt;
}
int main(){
int kase = 0;
while(scanf("%d%d",&n,&m) == 2){
memset(H,0,sizeof(H));
memset(V,0,sizeof(V));
memset(record,0,sizeof(record));
int a,b;
while(m--){
c = readchar();
scanf("%d %d",&a,&b);
if(c == 'H') H[a][b]= 1;
if(c == 'V') V[b][a]= 1;
}
if(++kase > 1) printf("\n**********************************\n\n");
printf("Problem #%d\n\n",kase);
int mark = 0;
for(int i = 1;i <= n;i++){
a = countsq(i);
if(a){
mark = 1;
printf("%d square (s) of size %d\n",a,i);
}
}
if(!mark) printf("No completed squares can be found.\n");
}
return 0;
}
这次总算AC了,但是没想到时间竟然是30ms,可能减少的时间还没有增加两个判断语句增加的时间多。。。