【wikioi】1174靶形数独
2014-05-14 21:23
387 查看
DFS爆搜,相当慢……
加了一些优化,使用集合来进行表示,比单纯地暴搜快了一倍
加上了启发式搜索函数
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> const int M = 10; const int p[10][10] = { {0,0,0,0,0,0,0,0,0,0}, {0,6,6,6,6,6,6,6,6,6}, {0,6,7,7,7,7,7,7,7,6}, {0,6,7,8,8,8,8,8,7,6}, {0,6,7,8,9,9,9,8,7,6}, {0,6,7,8,9,10,9,8,7,6}, {0,6,7,8,9,9,9,8,7,6}, {0,6,7,8,8,8,8,8,7,6}, {0,6,7,7,7,7,7,7,7,6}, {0,6,6,6,6,6,6,6,6,6} }; const int w[10][10]={ {0,0,0,0,0,0,0,0,0,0}, {0,1,1,1,2,2,2,3,3,3}, {0,1,1,1,2,2,2,3,3,3}, {0,1,1,1,2,2,2,3,3,3}, {0,4,4,4,5,5,5,6,6,6}, {0,4,4,4,5,5,5,6,6,6}, {0,4,4,4,5,5,5,6,6,6}, {0,7,7,7,8,8,8,9,9,9}, {0,7,7,7,8,8,8,9,9,9}, {0,7,7,7,8,8,8,9,9,9} }; int a[M][M]; int line[M][M]; int column[M][M]; int pane[M][M]; int b[M*M+9][2]; long long ans=0; int t; int find1(long long x,long long tot){//x为空点的数量 int x1,y1,y; int i,j; if(x==0){ if(tot>ans){ ans=tot; } return 0; } t++; if(t>12345000) return 0;//卡点小时 for(i=1;i<M;i++){ if(line[i][b[x][0]]==0&&column[i][b[x][1]]==0&&pane[w[b[x][0]][b[x][1]]][i]==0){//这个空点填这个数字 不在该行,不在该列,不在该宫 x1=b[x][0]; y1=b[x][1]; y=w[x1][y1]; line[i][x1]=1; column[i][y1]=1; pane[y][i]=1; a[x1][y1]=i; find1(x-1,tot+a[x1][y1]*p[x1][y1]); line[i][x1]=0; column[i][y1]=0; pane[y][i]=0; } } return 0; } int count; int tot; int main(){ int i,j,k; for(i=1;i<M;i++){ for(j=1;j<M;j++){ scanf("%d",&a[i][j]); if(a[i][j]){ line[a[i][j]][i]=1; column[a[i][j]][j]=1; pane[w[i][j]][a[i][j]]=1; tot+=a[i][j]*p[i][j]; } else { b[++count][0]=i; b[count][1]=j; } } } find1(count,tot); if(ans==0) ans=-1; printf("%d\n",ans); system("pause"); return 0; }
加了一些优化,使用集合来进行表示,比单纯地暴搜快了一倍
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; int hang[10]={0};//表示在第i行的数字j是否出现 int lie[10]={0}; int gong[10]={0}; int sit[10][10]={ {0,0,0,0,0,0,0,0,0,0}, {0,1,1,1,2,2,2,3,3,3}, {0,1,1,1,2,2,2,3,3,3}, {0,1,1,1,2,2,2,3,3,3}, {0,4,4,4,5,5,5,6,6,6}, {0,4,4,4,5,5,5,6,6,6}, {0,4,4,4,5,5,5,6,6,6}, {0,7,7,7,8,8,8,9,9,9}, {0,7,7,7,8,8,8,9,9,9}, {0,7,7,7,8,8,8,9,9,9}, }; int score[10][10]={ {0,0,0,0,0,0,0,0,0,0}, {0,6,6,6,6,6,6,6,6,6}, {0,6,7,7,7,7,7,7,7,6}, {0,6,7,8,8,8,8,8,7,6}, {0,6,7,8,9,9,9,8,7,6}, {0,6,7,8,9,10,9,8,7,6}, {0,6,7,8,9,9,9,8,7,6}, {0,6,7,8,8,8,8,8,7,6}, {0,6,7,7,7,7,7,7,7,6}, {0,6,6,6,6,6,6,6,6,6}, }; int map[10][10]={0}; int b[82][2]={0}; int ans=0; void solve(int n,int r) { if(n==0) { ans=(r>ans?r:ans); return; } int x,y; x=b [0]; y=b [1]; int a,b; a=hang[x]|lie[y]|gong[sit[x][y]];//求并集 for(int i=1;i<=9;i++) { b=~(1<<i)*-1; if((a&b)==0)//双方没有共同元素 { hang[x]+=(1<<i),lie[y]+=(1<<i),gong[sit[x][y]]+=(1<<i); r+=score[x][y]*i; solve(n-1,r); r-=score[x][y]*i; hang[x]-=(1<<i),lie[y]-=(1<<i),gong[sit[x][y]]-=(1<<i); } } } int main(void) { freopen("in.txt","r",stdin); int r=0; int n=0; for(int i=1;i<=9;i++) { for(int j=1;j<=9;j++) { scanf("%d",&map[i][j]); if(map[i][j]) { hang[i]+=(1<<map[i][j]); lie[j]+=(1<<map[i][j]); gong[sit[i][j]]+=(1<<map[i][j]); r+=score[i][j]*map[i][j]; } else { n++; b [0]=i; b [1]=j; } } } solve(n,r); if(ans==0) ans=-1; printf("%d\n",ans); return 0; } /* 将每一个行、列或九宫的数据用集合来表示 */
加上了启发式搜索函数
/*------------------------------------- DFS. + 启发函数. -------------------------------------*/ //----------Source Program------------- #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #define MAX(a,b) a>b?a:b using namespace std; int Map[10][10] = {0}; //这个就不用解释了吧 int Nine[10][10] = {0}; //小九宫格里每个数的使用标记,小九宫格的编号左到右,上到下,1,2,3,4,5,6,7,8,9 int Line[10][10] = {0}; //行上每个数的使用标记 int Row[10][10] = {0}; //列上每个数的使用标记 int FQueL[10] = {0}; //被启发后的行访问顺序 int FQueR[10] = {0}; //被启发后的列访问顺序 int Value[10][10] = {0}; //地图各点的价值因子 int QueL[81] = {0}; // int QueR[81] = {0}; //与上面那个,是根据启发后制定的搜索顺序的行列参数 int QLen = 0; //搜索队列的长度 int Ans = -1; //最优解 int Count = 0; //废物变量,纪念原来我错误的写法,懒得删掉了 int Swap(int *a,int *b) { int o=*a; *a=*b; *b=o; } void Heu() //启发函数 { for(int i=1;i<=9;++i){ FQueL[i] = i; FQueR[i] = i; } for(int i=1;i<=8;++i) for(int j=9;j>=i+1;--j){ if(Line[FQueL[j]][0] > Line[FQueL[j-1]][0]) Swap(&FQueL[j],&FQueL[j-1]); if(Row[FQueR[j]][0] > Row[FQueR[j-1]][0]) Swap(&FQueR[j],&FQueR[j-1]); } for(int i=1;i<=9;++i) for(int j=1;j<=9;++j) if(Map[FQueL[i]][FQueR[j]] == 0){ QueL[QLen]=FQueL[i]; QueR[QLen]=FQueR[j]; QLen++; } // for(int i=1;i<=9;++i) // cout<<FQueL[i]<<' '<<Line[FQueL[i]][0]<<' '<<FQueR[i]<<' '<<Row[FQueR[i]][0]<<endl; } int belong(int i,int j) //判断行列参数为i,j的点属于哪一个九宫格。 { int xt = 0,yt = 0; for(int k=6;k>=0;k-=3){ if(i-k>0){xt=(k+3)/3;break;} } for(int k=6;k>=0;k-=3){ if(j-k>0){yt=(k+3)/3;break;} } // cout<<xt<<' '<<yt<<' '<<xt+(yt-1)*3<<endl; // cout<<i<<' '<<j<<' '<< yt+(xt-1)*3 <<endl; return yt+(xt-1)*3; } int Score() //成绩计算 { int Temp = 0; for(int i=1;i<=9;++i) for(int j=1;j<=9;++j) Temp += Map[i][j]*Value[i][j]; Ans = MAX(Temp,Ans); // cout<<Ans<<endl; } int Dfs(int step) //深度优先搜索主体 { // cout<<step<<' '<<81-Count<<endl; // for(int i=1;i<=9;++i,cout<<endl) // for(int j=1;j<=9;++j) // cout<<Map[i][j]<<' '; if(step == QLen){Score();return 0;} if(!Map[QueL[step]][QueR[step]]) for(int k=1;k<=9;++k){ if(!Nine[belong(QueL[step],QueR[step])][k]) if(!Line[QueL[step]][k] && !Row[QueR[step]][k]){ //Heu(); // cout<<FQueL[i]<<' '<<FQueR[j]<<' '<<k<<endl; Map[QueL[step]][QueR[step]] = k; Nine[belong(QueL[step],QueR[step])][k] = 1; Line[QueL[step]][k]=Row[QueR[step]][k] = 1; Line[QueL[step]][0]++;Row[QueR[step]][0]++; Dfs(step+1); Map[QueL[step]][QueR[step]] = 0; Nine[belong(QueL[step],QueR[step])][k] = 0; Line[QueL[step]][k]=Row[QueR[step]][k] = 0; Line[QueL[step]][0]--;Row[QueR[step]][0]--; } } return 0; } int main() { for(int i=1;i<=5;++i) for(int j=1+(i-1);j<=9-(i-1);++j){ Value[i][j] = 6+(i-1); Value[9-(i-1)][j] = 6+(i-1); Value[j][9-(i-1)] = 6+(i-1); Value[j][i] = 6+(i-1); } //init value 对价值表的初始,好像其他人都是直接用{}初始的....... // for(int i=1;i<=9;++i,cout<<endl) // for(int j=1;j<=9;++j) // cout<<Value[i][j]<<' '; for(int i=1;i<=9;++i) for(int j=1,x,y;j<=9;++j){ scanf("%d",&Map[i][j]); if(Map[i][j] != 0 ){ Line[i][Map[i][j]] = 1; Line[i][0]++; Row[j][Map[i][j]] = 1; Row[j][0]++; Nine[belong(i,j)][Map[i][j]] = 1; Count++; } } // for(int i=1;i<=9;++i,cout<<endl) // for(int j=1;j<=9;++j) // cout<<Nine[i][j]; Heu(); Dfs(0); cout<<Ans; return 0; } DLX镇楼
<pre class="cpp" name="code" snippet_file_name="blog_20140514_3_8357491" code_snippet_id="345642">#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int maxc=324+10; const int maxr=729+10; const int maxnode=maxr*4+maxc; const int p[9][9]= { {6,6,6,6,6,6,6,6,6}, {6,7,7,7,7,7,7,7,6}, {6,7,8,8,8,8,8,7,6}, {6,7,8,9,9,9,8,7,6}, {6,7,8,9,10,9,8,7,6}, {6,7,8,9,9,9,8,7,6}, {6,7,8,8,8,8,8,7,6}, {6,7,7,7,7,7,7,7,6}, {6,6,6,6,6,6,6,6,6} }; struct DLX { int n,sz; int S[maxc]; int row[maxnode],col[maxnode],get[maxnode]; int L[maxnode],R[maxnode],U[maxnode],D[maxnode]; int ans; void init(int n) { this->n=n; for(int i=0;i<=n;i++) { U[i]=D[i]=i; L[i]=i-1; R[i]=i+1; } R =0; L[0]=n; sz=n+1; memset(S,0,sizeof S); } void addRow(int r,vector<int> columns,int _get) { int first=sz; for(int i=0;i<columns.size();i++) { int c=columns[i]; L[sz]=sz-1; R[sz]=sz+1; D[sz]=c; U[sz]=U[c]; D[U[c]]=sz; U[c]=sz; row[sz]=r; col[sz]=c; get[sz]=_get; S[c]++; sz++; } R[sz-1]=first; L[first]=sz-1; } #define FOR(i,A,s) for(int i=A[s];i!=s;i=A[i]) void remove(int c) { L[R[c]]=L[c]; R[L[c]]=R[c]; FOR(i,D,c) FOR(j,R,i) { U[D[j]]=U[j]; D[U[j]]=D[j]; S[col[j]]--; } } void restore(int c) { FOR(i,U,c) FOR(j,L,i) { S[col[j]]++; U[D[j]]=j; D[U[j]]=j; } L[R[c]]=c; R[L[c]]=c; } void dfs(int d,int score) { if(R[0]==0) { ans=max(ans,score); return; } int c=R[0]; b75b FOR(i,R,0) if(S[i]<S[c]) c=i; remove(c); FOR(i,D,c) { FOR(j,R,i) remove(col[j]); dfs(d+1,score+get[i]); FOR(j,L,i) restore(col[j]); } restore(c); } int solve() { ans=-1; dfs(0,0); return ans; } }; DLX solver; const int SLOT=0; const int ROW=1; const int COL=2; const int SUB=3; int encode(int a,int b,int c) { return a*81+b*9+c+1; } int puzzle[9][9]; int main() { for(int i=0;i<9;i++) for(int j=0;j<9;j++) scanf("%d",&puzzle[i][j]); solver.init(324); for(int r=0;r<9;r++) for(int c= 0;c<9;c++) for(int v=0;v<9;v++) if(puzzle[r][c]==0||puzzle[r][c]==v+1) { vector<int> columns; columns.push_back(encode(SLOT,r,c)); columns.push_back(encode(ROW,r,v)); columns.push_back(encode(COL,c,v)); columns.push_back(encode(SUB,(r/3)*3+c/3,v)); solver.addRow(encode(r,c,v),columns,p[r][c]*(v+1)); } printf("%d\n", solver.solve()); return 0; }
相关文章推荐
- wikioi1174 靶形数独 搜索
- [WIKIOI 1174]靶形数独(深度优先搜索)
- [codevs1174] 靶形数独
- 靶形数独(codevs 1174)
- codevs1174 靶形数独 dfs+剪枝
- Wiki OI 1174 靶形数独
- 靶形数独 (codevs 1174)题解
- wikioi-天梯-提高一等-启发式搜索-1074:靶形数独
- 【codevs1174】 靶形数独,暴力解决问题
- codevs 1174 靶形数独 2009年NOIP全国联赛提高组
- NOIP 2009 靶形数独 解题报告
- [NOIP2009]靶形数独【搜索】
- 【NOIP2009】洛谷1074 靶形数独
- 靶形数独
- [luoguP1074] 靶形数独(搜索)
- 洛谷 1074 [NOIP2009] 靶形数独 dfs+剪枝
- 洛谷P1074 靶形数独
- [noip2009]靶形数独
- 【NOIP 2009】靶形数独
- 洛谷 P1074 靶形数独