P1406 40分求助 蒟蒻已经改了两个小时了
查看原帖
P1406 40分求助 蒟蒻已经改了两个小时了
138608
白格Lifeplayer楼主2021/9/16 21:37
#include <iostream>
#include <algorithm>

using namespace std;
bool mrk[20];
int sto[20],suml[6],sumr[6],sum=0,ans[6][6];
int sumx1;int sumx2;
int n,cnt,j,N;

void judge()
{//最后检查方格填的数对不对
	for(int i=1;i<=n;i++)if(suml[i]!=sum)return;
	for(int i=1;i<=n;i++)if(sumr[i]!=sum)return;
	if(sumx1!=sum || sumx2!=sum)return;
	j=1;//如果合乎题意就标上,让dfs快速回溯
 }

 void prt()
 {//用来输出方格的样子的函数
 	for(int i=1;i<=n;i++)
 	{
 		for(int j=1;j<=n;j++)
 		{
 			if(j!=n)cout << ans[i][j] << ' ';
 			else cout << ans[i][j]<< endl;
		 }
	 }
	 cout << endl;
  }

void dfs(int x, int y)
{
	int dx, dy,s;
	if(x==n && y==n){judge();}//如果到头了就记录j=1来快速回溯
	if(y==n && suml[x]!=sum)return ;
	if(y==n)dx=x+1,dy=1;
	else dx=x,dy=y+1;//算出遍历的位置
	int i;
	for(i=1;i<=N;i++)
	{//遍历可以用的数
		if(!mrk[i])//如果该数没用过
		{
			s=sto[i];//记录当前遍历点的值
			suml[dx]+=s;//算行的总和
			sumr[dy]+=s;//算列的总和
			if(dx+dy-1==n)sumx1+=s;
			if(dx-dy+n==n)sumx2+=s;//如果点在对角线上就加上
			if(sum!=0 && (suml[dx]>sum || sumr[dy]>sum || sumx1>sum || sumx2>sum))
			{//要是加上这个点后超了sum了就还原后再遍历下一个值
				suml[dx]-=s;
				sumr[dy]-=s;
				if(dx+dy-1==n)sumx1-=s;
				if(dx-dy+n==n)sumx2-=s;
				if(i==N)return;//要是最后一个值都不行就返回
				continue;
			}
			//经过上述判断该值可用
			mrk[i]=1;//标记当前点用了
			ans[dx][dy]=s;//记录答案的方块长啥样
			dfs(dx,dy);
			if(j)return;//得出答案后快速回溯
			ans[dx][dy]=0;
			mrk[i]=0;
			suml[dx]-=s;
			sumr[dy]-=s;
			if(dx+dy-1==n)sumx1-=s;
			if(dx-dy+n==n)sumx2-=s;
			//以上六行都是dfs后用于复原的
		}
	}
}

int main()
{
	cin >> n;
	N =n*n;//算出总的数的个数
	for(int i=1;i<=N;i++)
	{
		cin >> sto[i];
		sum+=sto[i];
	}
	sum=sum/n;//算出sum的值
	sort(sto+1,sto+1+N);
	dfs(1, 0);
	cout << sum << endl;
	prt();
	return 0;
}

2021/9/16 21:37
加载中...