洛谷 1074 [NOIP2009] 靶形数独 dfs+剪枝
来源:互联网 发布:小米手机淘宝 编辑:程序博客网 时间:2024/06/05 04:11
题目:
https://www.luogu.org/problem/show?pid=1074
自己的代码70分(玄学倒搜);
改不出来看题解,长见识;
70分
正搜40,倒搜70,codevs卡时95!
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int ma[10][10],ans=-1,cnt,sum[10][10];bool can(int x,int y,int now){ int fx=0,fy=0; if(x<=3) fx=1; else if(x<=6) fx=4; else fx=7; if(y<=3) fy=1; else if(y<=6) fy=4; else fy=7; for(int i=1;i<=9;i++) if(ma[x][i]==now || ma[i][y]==now) return false; for(int i=fx;i<=fx+2;i++) for(int j=fy;j<=fy+2;j++) if(ma[i][j]==now) return false; return true;}void dfs(int x,int tot){ int fx=0,fy=0; if(x==0) { ans=max(ans,tot); return; } if(x%9==0) fx=x/9; else fx=x/9+1; fy=x-(fx-1)*9; if(ma[fx][fy]) dfs(x-1,tot+sum[fx][fy]*ma[fx][fy]); else for(int i=1;i<=9;i++) { if(can(fx,fy,i)) { ma[fx][fy]=i; dfs(x-1,tot+sum[fx][fy]*ma[fx][fy]); ma[fx][fy]=0; } } return;}void ji(){ for(int i=1;i<=9;i++) for(int j=1;j<=9;j++) sum[i][j]+=6; for(int i=2;i<=8;i++) for(int j=2;j<=8;j++) sum[i][j]+=1; for(int i=3;i<=7;i++) for(int j=3;j<=7;j++) sum[i][j]+=1; for(int i=4;i<=6;i++) for(int j=4;j<=6;j++) sum[i][j]+=1; sum[5][5]++; return;}void solve(){ int ss[10][10]; for(int i=1;i<=9;i++) for(int j=1;j<=9;j++) scanf("%d",&ma[i][j]); ji(); dfs(81,0); return;}int main(){ solve(); cout<<ans; return 0;}
正解:
启发式搜索+状压;
sum_hang[i] : 第i行大于0的数的个数;
lie[i]:第i列使用的数(状压);
hang[i]:第i行使用的数(状压);
ge[i]:第i个九宫个使用的数(状压);
ma:输入;
sum:得分;
un:没有填的格子的位置;
cnt:没填的格子个数;
思路:
预处理;
跳着搜每个没有填的位置,若全搜完即得到一个解;
这里的启发函数的意义:优先搜候选数少的格子,可以减少搜索树的大小;
状压:
对于某列111111001表示7,8个空没有填数;算是卡常吧;
收获:
1. |的回溯用^;
2. 搜索可以跳着搜……;
3. 重载运算符的新姿势;
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int MAXN=1001,tmp=(1<<9)-1;int sum_hang[MAXN],lie[MAXN],hang[MAXN],ge[MAXN],ma[MAXN][MAXN],sum[MAXN][MAXN];int cnt,ans=-1,tot,num;struct hh{ int x,y; bool operator < (hh t) const { if(sum_hang[x]==sum_hang[t.x]) return x < t.x; return sum_hang[x]>sum_hang[t.x]; }}un[MAXN];void ji(){ for(int i=0;i<9;i++) for(int j=0;j<9;j++) sum[i][j]+=6; for(int i=1;i<8;i++) for(int j=1;j<8;j++) sum[i][j]+=1; for(int i=2;i<7;i++) for(int j=2;j<7;j++) sum[i][j]+=1; for(int i=3;i<6;i++) for(int j=3;j<6;j++) sum[i][j]+=1; sum[4][4]++; return;}int gets(int x,int y){ return (x/3*3)+(y/3);//第几个九宫格;}void dfs(int cur,int tot){ if(cur>cnt) { ans=max(ans,tot); return; } int x=un[cur].x,y=un[cur].y; int temp=(hang[x]|(lie[y]|ge[gets(x,y)]));//寻找可用的数,简洁迅速; if(temp==tmp) return; for(int i=1;i<=9;i++) { if(!((temp>>(i-1))&1)) { int ss=1<<(i-1); ma[x][y]=i; hang[x]|=ss; lie[y]|=ss; ge[gets(x,y)]|=ss; dfs(cur+1,tot+ma[x][y]*sum[x][y]); hang[x]^=ss;//回溯用^; lie[y]^=ss; ge[gets(x,y)]^=ss; ma[x][y]=0; } } return;}void solve(){ ji(); for(int i=0;i<9;i++) for(int j=0;j<9;j++) { scanf("%d",&ma[i][j]); if(ma[i][j]) { num+=ma[i][j]*sum[i][j]; hang[i]|=(1<<(ma[i][j]-1)); lie[j]|=(1<<(ma[i][j]-1)); ge[gets(i,j)]|=(1<<(ma[i][j]-1)); sum_hang[i]++; } } for(int i=0;i<9;i++) for(int j=0;j<9;j++) if(!ma[i][j]) cnt++,un[cnt].x=i,un[cnt].y=j; sort(un+1,un+cnt+1);//优先级排序; dfs(1,num); cout<<ans;}int main(){ solve(); return 0;}
好像可以用跳舞链做(也就比这份代码快一点点),但是不会,%会的dalao;
阅读全文
1 0
- 洛谷 1074 [NOIP2009] 靶形数独 dfs+剪枝
- 【NOIP2009】洛谷1074 靶形数独
- 【NOIP2009】【CJOJ1687】【洛谷1074】靶形数独
- NOIP2009靶形数独(DFS)
- 【NOIP2009提高组T4】靶形数独-DFS剪枝+位运算优化
- NOIP2009 靶形数独
- NOIP2009 靶形数独
- NOIP2009 靶形数独
- NOIP2009靶形数独
- noip2009靶形数独
- noip2009靶形数独
- [noip2009]靶形数独
- 【题】【搜索(预处理剪枝)】NOIP2009 靶形数独
- codevs1174 靶形数独 dfs+剪枝
- 靶形数独(dfs+剪枝)
- 洛谷P1074 [Noip2009]靶形数独
- NOIP2009靶形数独——位运算优化DFS
- [DLX] [NOIP2009] 靶形数独
- 高性能滚动 scroll 及页面渲染优化
- cookie简单版
- (算法分析Week3)Pow(x,n)[Medium]
- 线段树之一段区间求两个数ax*ay的最小值
- Linux常用命令总结
- 洛谷 1074 [NOIP2009] 靶形数独 dfs+剪枝
- 深度学习网络卷积在GPU上的优化
- 数据结构思维 第十五章 爬取维基百科
- Eclipse Neon
- 理解正向代理和反向代理
- ubuntu kde Plasma5 图标无法自定义问题
- C#绘制圆角矩形
- springboot vue 安装 每天进步百分之一
- cannot be read or is not a valid ZIP file