csuoj2279 Pinemi Puzzles(dfs+剪枝)
题目大意
给出一个 的数字阵,其中一些空格填上了数字,一些格子留空,现在对留空的位置放入1-3根的棒子,要求每行每列的棒子数量 之和均为10,且所有有数字的格子以其为中心的九宫格中的棒子的数量之和为数字
解题思路
对所有的数字和每行每列列出方程,由于棒数在1-3之间,因此直接dfs搜索解即可,但是直接搜索肯定会超时,因此需要加上一些剪枝.若方程组中的一个子方程剩余的未枚举的未知数的数量大于剩余的所需的未知数的和或者剩余的所需的未知数的和大于剩余的未枚举的未知数的数量的三倍则也一定无解.
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
vector<pii> v;
map<pii,int> mp;
vector<int> lno[205];
int lim[205];
int tot[205];
int mat[15][15];
bool finish;
int mov[8][2]={{0,1},{0,-1},{1,0},{-1,0},{1,1},{-1,1},{1,-1},{-1,-1}};
int Hash(int i,int j)
{
return (i-1)*10+j;
}
void print()
{
for(int i=1;i<=10;i++)
{
for(int j=1;j<=10;j++)
{
printf("%d%c",mat[i][j],j==10?'\n':' ');
}
}
}
bool check(int x,int y)
{
if(x>=1&&x<=10&&y>=1&&y<=10) return true;
return false;
}
bool change_tag(int no,int cnt)
{
bool flag=true;
int cnts;
if(cnt>0) cnts=1;else cnts=-1;
for(auto x:lno[no])
{
tot[x]-=cnts;
lim[x]-=cnt;
if(lim[x]<tot[x]||lim[x]>3*tot[x]) {flag=false;}
}
return flag;
}
void dfs(int step)
{
if(step==v.size()||finish)
{
finish=true;
return ;
}
for(int i=1;i<=3;i++)
{
mat[v[step].first][v[step].second]=i;
if(change_tag(Hash(v[step].first,v[step].second),i))
dfs(step+1);
if(finish) return ;
change_tag(Hash(v[step].first,v[step].second),-i);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int kace;
finish=false;
scanf("%d",&kace);
printf("%d\n",kace);
memset(tot,0,sizeof(tot));
v.clear();
for(int i=0;i<=200;i++) lno[i].clear();
for(int i=1;i<=20;i++) lim[i]=10;
for(int i=1;i<=10;i++)
for(int j=1;j<=10;j++)
{
scanf("%d",&mat[i][j]);
if(mat[i][j]==-1)
{
v.push_back(pii(i,j));
lno[Hash(i,j)].push_back(i);
lno[Hash(i,j)].push_back(j+10);
tot[i]++;
tot[j+10]++;
}
}
for(int i=1;i<=10;i++)
{
for(int j=1;j<=10;j++)
{
if(mat[i][j]==-1) continue;
lim[Hash(i,j)+21]=mat[i][j];
for(int k=0;k<8;k++)
{
int ii=i+mov[k][0];
int jj=j+mov[k][1];
if(check(ii,jj)&&mat[ii][jj]==-1)
{
lno[Hash(ii,jj)].push_back(Hash(i,j)+21);
tot[Hash(i,j)+21]++;
}
}
}
}
dfs(0);
print();
}
}