今天学习了一个巧妙的构造题目:ural 1667 Square Country 3
要求构造一个矩阵满足元素不重复而且每个元素、每行的和、每列的和都是完全平方数。
做法是随机构造第一行b[1..m]和第一列a[1..n],然后矩阵c[i][j]=a[i]*b[j],这样是满足条件的。
不过为什么随机构造能够很快出解我还不会证明,希望有爱的同学补上。。
要求构造一个矩阵满足元素不重复而且每个元素、每行的和、每列的和都是完全平方数。
做法是随机构造第一行b[1..m]和第一列a[1..n],然后矩阵c[i][j]=a[i]*b[j],这样是满足条件的。
不过为什么随机构造能够很快出解我还不会证明,希望有爱的同学补上。。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<set>
using namespace std;
#define NN 30
const int K=300;
int cas,tcas;
int a[NN],b[NN],n,m;
long long c[NN][NN];
int sq[K+100];
int us[K+100];
int sv[NN];
void pre(){
int i;
for(i=1;i<=K+10;++i){
sq[i]=i*i;
}
}
int issqr(int n){
int tmp=sqrt(n);
if (tmp*tmp==n||(tmp+1)*(tmp+1)==n) return 1;
return 0;
}
void gao(int a[],int n){
int i,tmp,sum,flag=0;
while(1){
sum=0;
for(i=1;i<n;++i){
while(1) {tmp=rand()%K+10;if (!us[tmp]) break;}
a[i]=sq[tmp];
sv[i]=tmp;
us[tmp]=1;
sum+=a[i];
}
for(i=1;i<=K;++i)if (!us[i]){
if (issqr(sum+sq[i])){
us[i]=1;a[n]=sq[i];
flag=1;break;
}
}
if (flag==1) break;
for(i=1;i<n;++i){
us[sv[i]]=0;
}
}
}
set<long long> st;
int check(int n,int m){
int i,j;
st.clear();
for(i=1;i<=n;++i){
for(j=1;j<=m;++j){
if (st.find(c[i][j])!=st.end()) return 0;
st.insert(c[i][j]);
}
}
return 1;
}
int main(){
//freopen("1667in.txt","r",stdin);
int i,j;
pre();
srand(time(NULL));
scanf("%d",&tcas);
for(cas=1;cas<=tcas;++cas){
scanf("%d%d",&n,&m);
while(1){
memset(us,0,sizeof(us));
gao(a,n);
//for(i=1;i<=n;++i){printf("%d ",a[i]);}puts("111");
gao(b,m);
//for(i=1;i<=m;++i){printf("%d ",b[i]);}puts("");
for(i=1;i<=n;++i){
for(j=1;j<=m;++j){
c[i][j]=(long long)a[i]*b[j];
}
}
if (check(n,m)) break;
}
//while(1);
//printf(" cas=%d\n",cas);
for(i=1;i<=n;++i){
for(j=1;j<=m;++j){
printf("%I64d",c[i][j]);
if (j!=m) printf(" ");
else printf("\n");
}
}
if (cas!=tcas) printf("\n");
}
return 0;
}