UVA - 11214 Guarding the Chessboard (可重复覆盖,DLX+IDA*)

题目链接

正解是IDA*+四个方向判重,但由于是个裸的可重复覆盖问题,可以用DLX水过~

每个格子与放上皇后能干掉的标记连边,跑可重复覆盖DLX。注意要用IDA*来优化,否则会超时。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=10+2;
 5 int n,m,np,ka;
 6 char s[N][N];
 7 struct P {int x,y;} p[N*N];
 8 bool ok(P a,P b) {
 9     if(a.x==b.x)return 1;
10     if(a.y==b.y)return 1;
11     if(abs(a.x-b.x)==abs(a.y-b.y))return 1;
12     return 0;
13 }
14
15 struct DLX {
16     static const int N=1000;
17     static const int M=1000;
18     static const int MX=10000;
19     int n,tot,S[M],H[N],vis[M];
20     int row[MX],col[MX],L[MX],R[MX],U[MX],D[MX];
21     void init(int _n) {
22         n=_n;
23         for(int i=0; i<=n; ++i) {
24             U[i]=D[i]=i;
25             L[i]=i-1,R[i]=i+1;
26         }
27         L[0]=n,R[n]=0;
28         tot=n+1;
29         memset(S,0,sizeof S);
30         memset(H,-1,sizeof H);
31         memset(vis,0,sizeof vis);
32     }
33     void link(int r,int c) {
34         int u=tot++;
35         S[c]++;
36         row[u]=r,col[u]=c;
37         U[u]=U[c],D[u]=c;
38         U[D[u]]=D[U[u]]=u;
39         if(!~H[r])H[r]=L[u]=R[u]=u;
40         else {
41             R[u]=H[r],L[u]=L[H[r]];
42             L[R[u]]=R[L[u]]=u;
43         }
44     }
45     void remove(int c) {
46         for(int i=D[c]; i!=c; i=D[i])L[R[i]]=L[i],R[L[i]]=R[i];
47     }
48     void restore(int c) {
49         for(int i=U[c]; i!=c; i=U[i])L[R[i]]=R[L[i]]=i;
50     }
51     int h() {
52         int ret=0;
53         for(int c=R[0]; c!=0; c=R[c])vis[c]=1;
54         for(int c=R[0]; c!=0; c=R[c])if(vis[c]) {
55                 ++ret,vis[c]=0;
56                 for(int i=D[c]; i!=c; i=D[i])
57                     for(int j=R[i]; j!=i; j=R[j])vis[col[j]]=0;
58             }
59         return ret;
60     }
61     void check() {
62         for(int c=1; c<=n; ++c)if(!S[c]) {
63                 for(int i=D[c]; i!=c; i=D[i])L[R[i]]=L[i],R[L[i]]=R[i];
64                 L[R[c]]=L[c],R[L[c]]=R[c];
65             }
66     }
67     bool dfs(int dep,int mxd) {
68         if(R[0]==0)return 1;
69         if(dep+h()>mxd)return 0;
70         int c=R[0];
71         for(int i=R[0]; i!=0; i=R[i])if(S[i]<S[c])c=i;
72         for(int i=D[c]; i!=c; i=D[i]) {
73             remove(i);
74             for(int j=R[i]; j!=i; j=R[j])remove(j);
75             if(dfs(dep+1,mxd))return 1;
76             for(int j=L[i]; j!=i; j=L[j])restore(j);
77             restore(i);
78         }
79         return 0;
80     }
81     int IDAStar() {for(int mxd=0;; ++mxd) {if(dfs(0,mxd))return mxd;}}
82 } dlx;
83
84 int main() {
85     while(scanf("%d%d",&n,&m)&&n) {
86         np=0;
87         for(int i=0; i<n; ++i)scanf("%s",s[i]);
88         for(int i=0; i<n; ++i)
89             for(int j=0; j<m; ++j)if(s[i][j]==‘X‘)p[np++]= {i,j};
90         dlx.init(np);
91         for(int i=0; i<n; ++i)
92             for(int j=0; j<m; ++j)
93                 for(int k=0; k<np; ++k)
94                     if(ok({i,j}, p[k]))dlx.link(i*m+j+1,k+1);
95         printf("Case %d: %d\n",++ka,dlx.IDAStar());
96     }
97     return 0;
98 }

原文地址:https://www.cnblogs.com/asdfsag/p/10375228.html

时间: 2024-08-02 11:22:25

UVA - 11214 Guarding the Chessboard (可重复覆盖,DLX+IDA*)的相关文章

UVA 11214 Guarding the Chessboard 守卫棋盘(迭代加深+剪枝)

就是个暴力,和八皇后很像,但是还是要加一些的剪枝的. 1.最裸的暴搜 6.420s,差点超时 2.之前位置放过的就没必要在放了,每次从上一次放的位置开始放 0.400s #include<cstdio> #include<cstring> const int maxn = 11; char G[maxn][maxn]; int maxd; int n,m; bool visi[maxn],visj[maxn],vis1[maxn<<1],vis2[maxn<<

hdu - 4979 - A simple math problem.(可重复覆盖DLX + 打表)

题意:一种彩票共有 N 个号码,每注包含 M 个号码,如果开出来的 M 个号码中与自己买的注有 R 个以上的相同号码,则中二等奖,问要保证中二等奖至少要买多少注(1<=R<=M<=N<=8). 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4979 -->>覆盖问题,yy可知是可重复覆盖问题,于是,DLX 上场.. N个 选 R 个,共有 C[N][R] 种选法,每种选法需要被覆盖,对应于 DLX 中的列.. N个 选 M

hdu - 3498 - whosyourdaddy(重复覆盖DLX)

题意:N(2 ≤ N ≤ 55)个点,M(0 ≤ M ≤ N*N)条无向边,删除一个点会把与其相邻的点一起删掉,问最少删几次可以删掉所有点. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3498 -->>N个点看成 N 个要被覆盖的列,每个点作为一行,与其相邻的点的位置在这一行中标为 1,还有它自已的位置也标记为 1.. 这就是经典的重复覆盖问题了..于是,DLX上场.. #include <cstdio> #include <

11214 - Guarding the Chessboard(暴力搜索)

IDA*算法, 从小到大枚举深度上限,不过该题是有深度上限的,题目中的第一个样例表明:最多需要5个皇后就可以覆盖整个棋盘 . 利用紫书上的技巧,我们可以快速的判断任意两个棋子是不是在同一行.同一列.同一对角线 (详情见紫书P193那两个图). 这样之后暴力搜索就可以了 . 每一层需要O(nm)的复杂度,但是实际上并不需要那么大的复杂度 .和八皇后问题类似 , 当前行之前的行已经放置了皇后,所以不必在管,每次从下一行开始放置就好 . 细节见代码: #include<bits/stdc++.h>

HDU 3335 Divisibility dancing links 重复覆盖

分析: dlx重复覆盖的巧用,重复覆盖的原理恰好符合本题的筛选方式,即选择一个数后,该数的倍数或约数可以保证在之后的搜索中不会被选择 于是修改一下启发函数,求解最大的重复覆盖即可. 其实不一定不被选择,只是选择以后,要么达不成目标,要不达到目标,也不如不选择更优 举下面的例子 3 2 3 6 答案一看就是 2 初始的dancing links的表示是这样的 2   3   6 2    1   0   1 3    0   1   1 6    1   1   1 然后肯定先选第一列进行删 删

HDU 3335 Divisibility(DLX可重复覆盖)

Problem Description As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory.So,many people call him "the descendant of Chen Jingrun",which brings him a good reputation. AekdyCoin also plays an important role in th

HDU5046 Airport dancing links 重复覆盖+二分

这一道题和HDU2295是一样 是一个dancing links重复覆盖解决最小支配集的问题 在给定长度下求一个最小支配集,只要小于k就行 然后就是二分答案,每次求最小支配集 只不过HDU2295是浮点,这里是整数 我写的一个比较暴力 #include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector

[DLX重复覆盖] fzu 1686 神龙的难题

题意: 中文题 思路: 想到是一个重复覆盖的问题,然后就是最少放多少个能覆盖满. 建图的话就是先标记一下哪些点有怪物,最多就是n*m个怪物. 然后就是行. 行的话就看输入的x和y能框住多少的范围了. 然后四重循环遍历一遍建边就ok了. 代码: #include"stdio.h" #include"algorithm" #include"string.h" #include"iostream" #include"cma

poj 1084 Square Destroyer dlx解重复覆盖

分析: 将问题转化为重复覆盖问题,DancingLink解决. 代码: //poj 1084 //sep9 #include <iostream> using namespace std; const int maxN=10024; const int maxL=128; int L[maxN],R[maxN],U[maxN],D[maxN]; int C[maxN],H[maxN]; int S[maxN],A[maxN],X[maxN]; bool makeup[maxL][maxL];