LightOJ 1061 N Queen Again(记忆化搜索)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1061

题意:给定8*8的棋盘上8个皇后。挪动最少的步数使得不互相攻击?

思路:首先预处理求出所有的合法放法(就是这里一开始想了好久没想出来)。然后对于每个测试数据,枚举每一种合法放法。。。枚举的时候记忆化搜索和直接BFS都行,前一种快点。。

 

View Code
  1 //记忆化搜索
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #define min(x,y) ((x)<(y)?(x):(y))
  6 using namespace std;
  7  
  8 struct node
  9 {
 10     int x[10],y[10];
 11 };
 12  
 13 node ans[1000],p;
 14 int sum;
 15 int C,num=0;
 16 char s[10][10];
 17  
 18 int abs(int x)
 19 {
 20     return x>0?x:-x;
 21 }
 22  
 23 inline int OK(int x,int y,node a,int n)
 24 {
 25     int i;
 26     for(i=1;i<=n;i++) if(a.y[i]==y||abs(a.x[i]-x)==abs(a.y[i]-y))
 27        return 0;
 28     return 1;
 29 }
 30  
 31 void DFS(int dep,node &a)
 32 {
 33     if(dep==9)
 34     {
 35         ans[++sum]=a;
 36         return;
 37     }
 38     int i;
 39     for(i=1;i<=8;i++) if(OK(dep,i,a,dep-1))
 40     {
 41         a.x[dep]=dep;
 42         a.y[dep]=i;
 43         DFS(dep+1,a);
 44     }
 45 }
 46  
 47 void init()
 48 {
 49     sum=0;
 50     node a;
 51     DFS(1,a);
 52 }
 53  
 54 const int INF=1000000000;
 55 int f[10][300];
 56  
 57 inline int get(node a,int t1,node b,int t2)
 58 {
 59     int x1=a.x[t1],y1=a.y[t1];
 60     int x2=b.x[t2],y2=b.y[t2];
 61     if(x1==x2&&y1==y2) return 0;
 62     if(x1==x2||y1==y2||abs(x1-x2)==abs(y1-y2)) return 1;
 63     return 2;
 64 }
 65  
 66 int DFS1(int u,int st,node a)
 67 {
 68     if(u==8) return 0;
 69     if(f[u][st]!=-1) return f[u][st];
 70     int i,t=INF;
 71     for(i=0;i<8;i++) if(0==(st&(1<<i)))
 72         t=min(t,get(p,u+1,a,i+1)+DFS1(u+1,st|(1<<i),a));
 73     return f[u][st]=t;
 74 }
 75  
 76 int deal()
 77 {
 78     int temp=INF,i;
 79     for(i=1;i<=sum;i++)
 80     {
 81         memset(f,-1,sizeof(f));
 82         temp=min(temp,DFS1(0,0,ans[i]));
 83     }
 84     return temp;
 85 }
 86  
 87 int main()
 88 {
 89     init();
 90     for(scanf("%d",&C);C--;)
 91     {
 92         int i,j,k=0;
 93         for(i=1;i<=8;i++)
 94         {
 95             scanf("%s",s[i]+1);
 96             for(j=1;j<=8;j++) if(s[i][j]=='q')
 97             {
 98                 p.x[++k]=i;
 99                 p.y[k]=j;
100             }
101         }
102         printf("Case %d: %d\n",++num,deal());
103     }
104     return 0;
105 }
106 
107 //直接BFS
108 #include <iostream>
109 #include <cstdio>
110 #include <cstring>
111 #include <queue>
112 #define min(x,y) ((x)<(y)?(x):(y))
113 using namespace std;
114 
115 struct node
116 {
117     int x[10],y[10];
118 };
119 
120 node ans[1000],p;
121 int sum;
122 int C,num=0;
123 char s[10][10];
124 
125 int abs(int x)
126 {
127     return x>0?x:-x;
128 }
129 
130 inline int OK(int x,int y,node a,int n)
131 {
132     int i;
133     for(i=1;i<=n;i++) if(a.y[i]==y||abs(a.x[i]-x)==abs(a.y[i]-y))
134         return 0;
135     return 1;
136 }
137 
138 void DFS(int dep,node &a)
139 {
140     if(dep==9)
141     {
142         ans[++sum]=a;
143         return;
144     }
145     int i;
146     for(i=1;i<=8;i++) if(OK(dep,i,a,dep-1))
147     {
148         a.x[dep]=dep;
149         a.y[dep]=i;
150         DFS(dep+1,a);
151     }
152 }
153 
154 void init()
155 {
156     sum=0;
157     node a;
158     DFS(1,a);
159 }
160 
161 
162 
163 inline int get(node a,int t1,node b,int t2)
164 {
165     int x1=a.x[t1],y1=a.y[t1];
166     int x2=b.x[t2],y2=b.y[t2];
167     if(x1==x2&&y1==y2) return 0;
168     if(x1==x2||y1==y2||abs(x1-x2)==abs(y1-y2)) return 1;
169     return 2;
170 }
171 
172 const int INF=1000000000;
173 int f[66000],visit[66000];
174 
175 int cal(node a,node b)
176 {
177     int k,aa,bb,k0,aa0,bb0,i,j,cost;
178     queue<int> Q;
179     memset(f,-1,sizeof(f));
180     memset(visit,0,sizeof(visit));
181     f[255]=0;
182     visit[255]=1;
183     Q.push(255);
184     while(!Q.empty())
185     {
186         k=Q.front();
187         Q.pop();
188         visit[k]=0;
189         aa=k>>8;
190         bb=k&255;
191         for(i=0;i<8;i++) if(bb&(1<<i))
192         {
193             for(j=0;j<8;j++) if(0==(aa&(1<<j)))
194             {
195                 aa0=aa^(1<<j);
196                 bb0=bb^(1<<i);
197                 k0=(aa0<<8)+bb0;
198                 cost=get(b,i+1,a,j+1);
199                 if(f[k0]==-1||f[k0]>f[k]+cost)
200                 {
201                     f[k0]=f[k]+cost;
202                     if(!visit[k0])
203                     {
204                         Q.push(k0);
205                         visit[k0]=1;
206                     }
207                 }
208             }
209             break;
210         }
211     }
212     return f[255<<8];
213 }
214 
215 int deal()
216 {
217     int temp=INF,i;
218     for(i=1;i<=sum;i++)
219     {
220         memset(f,-1,sizeof(f));
221         temp=min(temp,cal(ans[i],p));
222     }
223     return temp;
224 }
225 
226 int main()
227 {
228     init();
229     for(scanf("%d",&C);C--;)
230     {
231         int i,j,k=0;
232         for(i=1;i<=8;i++)
233         {
234             scanf("%s",s[i]+1);
235             for(j=1;j<=8;j++) if(s[i][j]=='q')
236             {
237                 p.x[++k]=i;
238                 p.y[k]=j;
239             }
240         }
241         printf("Case %d: %d\n",++num,deal());
242     }
243     return 0;
244 }

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sigma函数是指一个数字的所有因子之和。给定一个数字n,需要求出有多少个数字的Sigma函数是偶数。\[2\] 为了解决这个问题,可以先筛选出n范围内的素数(范围在10^6即可),然后对n进行素因子分解。对于每个因子,如果它的Sigma函数中连乘的每一项都是偶数,那么整个Sigma函数就是偶数。具体实现中,可以判断每个因子的平方根是否为偶数,如果是偶数,则减去(平方根+1)/2。\[1\] 另外,还可以使用O(1)的做法来解决这个问题。根据观察,所有的完全平方数及其两倍的值都会导致Sigma函数为偶数。因此,可以直接计算n的平方根,然后减去(平方根+1)/2即可得到结果。\[3\] #### 引用[.reference_title] - *1* [Sigma Function](https://blog.csdn.net/PNAN222/article/details/50938232)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【LightOJ1336】Sigma Function(数论)](https://blog.csdn.net/qq_30974369/article/details/79009498)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值