Palindromic Matrix(构造法)-CodeForces div2 540C

题目传送门
题意:
题目就是给你一组序列要你利用这些数构造出一个上下对称,左右也对称的n*n矩阵。若不能,输出NO,否则输出YES,并输出够早的矩阵。
思路:
比赛的时候,自己求快,稍微有点头目就开始动笔,不愿意继续深入归纳(自己有点懒)。结果就是调试爆炸,代码超长。写出了一个垃圾代码。
像这种构造体,或者模拟题,一定要去找到不同情况之间的共性。归纳他们的相同点和不同点。比如这里分为n为奇数和偶数两种情况。偶数简单,开始分成4块,用数字填写那对称的4块时,他们两个可以共用一些代码。
下面n为奇数时,要特别处理中间的,中间的至少要2个,中心1个。对称的4块要4个。
还有就是找数,可以用一个通用函数get_sum,不管找几个,只要找到后,就把相应的数的次数减去相应的个数,然后返回。找不到就返回NO的标记值。
自己的思维还是局限,没有养成抽象的习惯,总是翻译简单易懂的逻辑,没有用另一种稍微转一下弯的逻辑(旺旺可以简化代码,减低出错率)。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<cstring>
#include<string>
#include<cmath>

using namespace std;

typedef long long LL;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i = a;i <= b;++i)
#define rep(i,a,b) for(int i = a;i >= b;--i)
const int maxn = 20;
int n = 0,m = 0;
map<int,int> mp;
int a[maxn+10][maxn+10];
int get_num(int cnt){
	map<int,int>::iterator it = mp.begin();
	for(it = mp.begin();it != mp.end();++it){
		if(it->second >= cnt){
			it->second -= cnt;
			return it->first;
		}
	}
	return -1;
}
void solve(){
	per(i,1,n/2){//n为偶数和奇数都是用的情况 
		per(j,1,n/2){
			int num = get_num(4);
			if(num == -1){
				printf("NO\n");
				return ;
			}
			a[i][j] = a[n+1-i][j] = a[i][n+1-j] = a[n+1-i][n+1-j] = num;
		}
	}
	
	if(n & 1){//奇数要处理中间行和列 
		per(i,1,n/2){
			int num = get_num(2);
			if(num == -1){
				printf("NO\n");
				return ;
			}
			a[i][(n+1)/2] = a[n+1-i][(n+1)/2] = num;
			num = get_num(2);
			if(num == -1){
				printf("NO\n");
				return ;
			}
			a[(n+1)/2][i] = a[(n+1)/2][n+1-i] = num;
		}
		int num = get_num(1);
		if(num == -1){
				printf("NO\n");
				return ;
			}
		a[(n+1)/2][(n+1)/2] = num; 
	}
	printf("YES\n");
	per(i,1,n){
		per(j,1,n){
			printf("%d%c",a[i][j],j == n ? '\n' : ' ');
		}
	}
	
}
int main(){
	while(~scanf("%d",&n)){
		mp.clear();
		per(i,1,n*n){
			int x = 0;
			scanf("%d",&x);
			++mp[x];		
		}
		solve();
	}
	
	return 0;
}

垃圾AC代码(没有归纳好):

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<cstring>
#include<string>
#include<cmath>

using namespace std;

typedef long long LL;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i = a;i <= b;++i)
#define rep(i,a,b) for(int i = a;i >= b;--i)
const int maxn = 1e3;
int n = 0,m = 0;
//int times[maxn+10];
map<int,int> mp; 
int b[maxn+10];
int a[30][30];
void solve(){
	map<int,int>::iterator it = mp.begin();
	int num[maxn+10];
	int cnt = 0;
	if(n % 2 == 0){
		for(it = it;it != mp.end();++it){
			per(i,1,it->second / 4){
				num[++cnt] = it->first;
			}
		}
		int p = 0;
		per(i,1,n/2){
			per(j,1,n/2){
				a[i][j] = num[++p];
			}
		}
		per(i,1,n/2){
			per(j,n/2+1,n){
				a[i][j] = a[i][n+1-j];
			}
		}
		per(i,n/2+1,n){
			per(j,1,n){
				a[i][j] = a[n+1-i][j];
			}
		}
	}else{
		int center = 0;
		int np2[maxn+10];
		int cnt = 0,cnt2 = 0;
		for(it = mp.begin();it != mp.end();++it){
			if(it->second & 1){
				center = it->first;
				it->second -= 1;
			}
			if(it->second >= 4){
				per(i,1,it->second/4){
					num[++cnt] = it->first;
				}
			}
			if(it->second % 4 == 2 && it->second != 0){//不可能只有1这一个小于4的数 
				np2[++cnt2] = it->first; 
			}
		}
		//cout << "na " <<cnt <<" " <<cnt2 << endl;
		if(cnt2 > n-1 && n != 1){
			printf("NO\n");
			return ;
		}
		int mid = (n+1)/2;
		a[mid][mid] = center;
		int pos = 1;
		bool flag = false;
		per(i,1,cnt2){
			a[pos][mid] = a[n+1-pos][mid] = np2[i];
			++pos;
			if(pos == mid){
				flag = true;
				break;
			}
		}
		bool flag2 = false;
		int k = 1;
		if(flag == true){
			pos = 1;
			per(i,n/2+1,cnt2){
				a[mid][pos] = a[mid][n+1-pos] = np2[i];
				++pos;
				if(pos == mid){
					flag2 = true;
					break;
				}
			}
			int ps = 0;
			if(flag2 == false){
				//cout << "hah" << endl;
				for(k = 1;k <= cnt;){
					//cout << "nihao " << k << " " <<pos << endl;
					a[mid][pos] = a[mid][n+1-pos] = num[k];
					++pos;++ps;
					if(ps % 2 == 0){
						++k;
					}
					if(pos == mid){
						break;
					}
					a[mid][pos] = a[mid][n+1-pos] = num[k];
					++pos;++ps;
					if(ps % 2 == 0){
						++k;
					}
					if(pos == mid){
						break;
					}
				
				}
			}
		//	cout << "nima " <<k << " " <<cnt << endl;
		}else{
			//cout << "po " << pos <<" " <<k << " " <<cnt << " " << cnt2 <<endl;
 			int ps = 0;
			//cout << "niam " << pos << "" << k << endl;
			for(k = 1;k <= cnt;){
			//	cout << pos <<" ji " << num[k] << endl;
				a[pos][mid] = a[n+1-pos][mid] = num[k];
				++pos;++ps;
				if(ps % 2 == 0){
					++k;
				}
				if(pos == mid){
					break;
				}
				a[pos][mid] = a[n+1-pos][mid] = num[k];
				++pos;++ps;
				if(ps % 2 == 0){
					++k;
				}
				if(pos == mid){
					break;
				}
			}
			pos = 1;
			for(k = k;k <= cnt;){
				a[mid][pos] = a[mid][n+1-pos] = num[k];
				++pos;++ps;
				if(ps % 2 == 0){
					++k;
				}
				if(pos == mid){
					break;
				}
				a[mid][pos] = a[mid][n+1-pos] = num[k];
				++pos;++ps;
				if(ps % 2 == 0){
					++k;
				}
				if(pos == mid){
					break;
				}
			}
		}
		int p = k;
			per(i,1,n/2){
				per(j,1,n/2){
					//if(i == n/2){
					//	cout <<"ko " << p <<" " << num[p] << endl;
					//}
					a[i][j] = num[p++];
				}
			}
			per(i,1,n/2){
				per(j,n/2+1,n){
					a[i][j] = a[i][n+1-j];
				}
			}
			per(i,n/2+1,n){
				per(j,1,n){
					a[i][j] = a[n+1-i][j];
				}
			}
		
	}
	printf("YES\n");
	per(i,1,n){
		per(j,1,n){
			printf("%d%c",a[i][j],j == n ? '\n': ' ');
		}
	}
}
int main(){
	while(~scanf("%d",&n)){
		mp.clear();
		per(i,1,n*n){
			scanf("%d",&b[i]);
			++mp[b[i]];
		}
		map<int,int>::iterator it = mp.begin();
		if(n % 2 == 0){
			for(it = it;it != mp.end();++it){
				if(it->second % 4 != 0){
					printf("NO\n");
					return 0;
				}
			}
		}else{
			int flag = 0;
			for(it = mp.begin();it != mp.end();++it){
				if(it->second & 1){
					++flag;
					if(flag > 1){
						printf("NO\n");
						return 0;
					}
				}
			}
		}
		solve();
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值