SPOJ 1771&&DLX精确覆盖,重复覆盖
DLX的题,做过这题才算是会吧。
这道题转化成了精确覆盖模型来做,一开始,只是单纯的要覆盖完行列和斜线,WA。
后来醒悟了,不能这样,只要覆盖全部行或列即可。虽然如此,但某些细节地方很关键不能考虑到。
特别要注意的是
for(int i=R[c];i;i=R[i]){ if(i>ne) break; if(S[i] < S[c]) c = i;}
找最小值只能是在ne之前,为什么呢?因为我们要完全覆盖行。可行吗?可行。稍微留意一下DLX的模板就知道,它其实在选中一列之后,是会枚举列上的行值,
也就是说,该列(代表棋盘某一行)的每一个们置都会考虑到,不必担心无解。
DLX这个算法很巧妙啊,其实它只是一种高效的剪枝吧。妙妙妙,做过这题后才算真正懂得这个算法。
#include<cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; const int maxn=500;
const int maxnode=500*2500;
int ne;
int anst[maxn];
struct DLX
{
int n , sz; // 行数,节点总数
int S[maxn]; // 各列节点总数
int row[maxnode],col[maxnode]; // 各节点行列编号
int L[maxnode],R[maxnode],U[maxnode],D[maxnode]; // 十字链表 int ansd,ans[maxn]; // 解 void init(int n )
{
this->n = n ;
for(int i = 0 ; i <= n; i++ )
{
U[i] = i ;
D[i] = i ;
L[i] = i - 1;
R[i] = i + 1;
}
R[n] = 0 ;
L[0] = n;
sz = n + 1 ;
memset(S,0,sizeof(S));
}
void addRow(int r,vector<int> c1)
{
int first = sz;
for(int i = 0 ; i < c1.size(); i++ ){
int c = c1[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;
S[c] ++ ; sz ++ ;
}
R[sz - 1] = first ; L[first] = sz - 1;
}
// 顺着链表A,遍历除s外的其他元素
#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;
}
bool dfs(int d){
if(d >= ne ){
ansd=d;
for(int i=0;i<ne;i++){
int x=(ans[i]-1)/ne+1;
int y=(ans[i]-1)%ne+1;
anst[x]=y;
}
printf("%d",anst[1]);
for(int i=2;i<=ne;i++)
printf(" %d",anst[i]);
printf("\n");
return true;
}
// 找S最小的列c
int c = R[0] ;
for(int i=R[c];i;i=R[i]){ if(i>ne) break; if(S[i] < S[c]) c = i;}
remove(c);
FOR(i,D,c){
ans[d] = row[i];
FOR(j,R,i) remove(col[j]);
if(dfs(d + 1)) return true;
FOR(j,L,i) restore(col[j]);
}
restore(c);
return false;
}
void solve(){
dfs(0);
}
}; DLX solver; int puzzle[100][100]; int main(){
int tmp;
while(scanf("%d",&ne)!=EOF){
memset(puzzle,0,sizeof(puzzle));
for(int k=1;k<=ne;k++){
scanf("%d",&tmp);
if(tmp>0){
for(int i=1;i<=ne;i++)
puzzle[k][i]=puzzle[i][tmp]=-1;
for(int i=1;k-i>0&&tmp-i>0;i++)
puzzle[k-i][tmp-i]=-1;
for(int i=1;k+i<=ne&&tmp+i<=ne;i++)
puzzle[k+i][tmp+i]=-1;
for(int i=1;k-i>0&&tmp+i<=ne;i++)
puzzle[k-i][tmp+i]=-1;
for(int i=1;k+i<=ne&&tmp-i>0;i++)
puzzle[k+i][tmp-i]=-1;
puzzle[k][tmp]=1;
}
}
solver.init(6*ne-2);
vector<int>columns;
for(int i=1;i<=ne;i++){
for(int j=1;j<=ne;j++){
columns.clear();
if(puzzle[i][j]>=0){
columns.push_back(i);
columns.push_back(ne+j);
columns.push_back(ne*2+j-1+i);
columns.push_back(ne*2+2*ne-1+ne-i+j);
solver.addRow((i-1)*ne+j,columns);
}
}
}
solver.solve();
}
return 0;
}
摘http://www.cnblogs.com/jh818012/p/3252154.html
重复覆盖模板
const int maxn=360000;
const int maxc=500;
const int maxr=500;
const int inf=0x3f3f3f3f;
int L[maxn], R[maxn], D[maxn], U[maxn], C[maxn];
int S[maxc], H[maxr], size;
///不需要S域
void Link(int r, int c)
{
S[c]++; C[size]=c;
U[size]=U[c]; D[U[c]]=size;
D[size]=c; U[c]=size;
if(H[r]==-1) H[r]=L[size]=R[size]=size;
else {
L[size]=L[H[r]]; R[L[H[r]]]=size;
R[size]=H[r]; L[H[r]]=size;
}
size++;
}
void remove(int c){
for (int i=D[c]; i!=c; i=D[i])
L[R[i]]=L[i], R[L[i]]=R[i];
}
void resume(int c){
for (int i=U[c]; i!=c; i=U[i])
L[R[i]]=R[L[i]]=i;
}
int h(){///用精确覆盖去估算剪枝
int ret=0;
bool vis[maxc];
memset (vis, false, sizeof(vis));
for (int i=R[0]; i; i=R[i])
{
if(vis[i])continue;
ret++;
vis[i]=true;
for (int j=D[i]; j!=i; j=D[j])
for (int k=R[j]; k!=j; k=R[k])
vis[C[k]]=true;
}
return ret;
} int ans;
void Dance(int k){ //根据具体问题选择限制搜索深度或直接求解。 A*算法,此处只求最优解
if(k+h()>=ans) return;
if(!R[0]){
if(k<ans)ans=k;
return;
}
int c=R[0];
for (int i=R[0]; i; i=R[i])
if(S[i]<S[c])c=i;
for (int i=D[c]; i!=c; i=D[i]){
remove(i);
for (int j=R[i]; j!=i; j=R[j])
remove(j);
Dance(k+1);
for (int j=L[i]; j!=i; j=L[j])
resume(j);
resume(i);
}
return ;
} void initL(int x){///col is 1~x,row start from 1
for (int i=0; i<=x; ++i){
S[i]=0;
D[i]=U[i]=i;
L[i+1]=i; R[i]=i+1;
}///对列表头初始化
R[x]=0;
size=x+1;///真正的元素从m+1开始
memset (H, -1, sizeof(H));
///mark每个位置的名字
} DLX 重复覆盖 template
精确覆盖模板
struct DLX
{
int n , sz; // 行数,节点总数
int S[maxn]; // 各列节点总数
int row[maxnode],col[maxnode]; // 各节点行列编号
int L[maxnode],R[maxnode],U[maxnode],D[maxnode]; // 十字链表 int ansd,ans[maxn]; // 解 void init(int n )
{
this->n = n ;
for(int i = 0 ; i <= n; i++ )
{
U[i] = i ;
D[i] = i ;
L[i] = i - 1;
R[i] = i + 1;
}
R[n] = 0 ;
L[0] = n;
sz = n + 1 ;
memset(S,0,sizeof(S));
}
void addRow(int r,vector<int> c1)
{
int first = sz;
for(int i = 0 ; i < c1.size(); i++ ){
int c = c1[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;
S[c] ++ ; sz ++ ;
}
R[sz - 1] = first ; L[first] = sz - 1;
}
// 顺着链表A,遍历除s外的其他元素
#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;
}
bool dfs(int d){
if(R[0] == 0 ){
ansd = d;
return true;
}
// 找S最小的列c
int c = R[0] ;
FOR(i,R,0) if(S[i] < S[c]) c = i; remove(c);
FOR(i,D,c){
ans[d] = row[i];
FOR(j,R,i) remove(col[j]);
if(dfs(d + 1)) return true;
FOR(j,L,i) restore(col[j]);
}
restore(c); return false;
}
bool solve(vector<int> & v){
v.clear();
if(!dfs(0)) return false;
for(int i = 0 ; i< ansd ;i ++ ) v.push_back(ans[i]);
return true;
}
}; DLX solver; int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
solver.init(m);
int c , x;
vector<int> c1;
for(int i = 1; i<= n ; i ++ )
{
scanf("%d",&c);
c1.clear();
for(int j = 0 ; j < c ; j ++ ){scanf("%d",&x);c1.push_back(x);}
solver.addRow(i,c1);
}
vector<int> ans;
bool flag ;
flag = solver.solve(ans);
if(flag )
{
int size1 = ans.size();
printf("%d",size1);
for(int i = 0 ; i < size1;i ++ )
printf(" %d",ans[i]);
printf("\n");
}
else printf("NO\n");
}
return 0;
}
SPOJ 1771&&DLX精确覆盖,重复覆盖的更多相关文章
- 【转】DLX 精确覆盖 重复覆盖
问题描述: 给定一个n*m的矩阵,有些位置为1,有些位置为0.如果G[i][j]==1则说明i行可以覆盖j列. Problem: 1)选定最少的行,使得每列有且仅有一个1. 2)选定最少的行,使得每列 ...
- dancing link 精确覆盖 重复覆盖 (DLX)
申明:因为转载的没有给出转载链接,我就把他的链接附上,请尊重原创: http://www.cnblogs.com/-sunshine/p/3358922.html 如果谁知道原创链接 给一下,请尊重原 ...
- HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)
很久以前就看到的一个经典题,一直没做,今天拿来练手.街霸 给n<=25个角色,每个角色有 1 or 2 个版本(可以理解为普通版以及爆发版),每个角色版本可以KO掉若干人. 问最少选多少个角色( ...
- DLX 舞蹈链 精确覆盖 与 重复覆盖
精确覆盖问题:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 还有重复覆盖问题 dancing links 是 一种数据结构,用来优化搜索,不算是一种算法.(双向 ...
- HDU 3957 Street Fighter (最小支配集 DLX 重复覆盖+精确覆盖 )
DLX经典题型,被虐惨了…… 建一个2*N行3*N列的矩阵,行代表选择,列代表约束.前2*N列代表每个人的哪种状态,后N列保证每个人至多选一次. 显然对手可以被战胜多次(重复覆盖),每个角色至多选择一 ...
- DLX精确覆盖与重复覆盖模板题
hihoCoder #1317 : 搜索四·跳舞链 原题地址:http://hihocoder.com/problemset/problem/1317 时间限制:10000ms 单点时限:1000ms ...
- zoj 3209.Treasure Map(DLX精确覆盖)
直接精确覆盖 开始逐行添加超时了,换成了单点添加 #include <iostream> #include <cstring> #include <cstdio> ...
- HDU 2295.Radar (DLX重复覆盖)
2分答案+DLX判断可行 不使用的估计函数的可重复覆盖的搜索树将十分庞大 #include <iostream> #include <cstring> #include < ...
- UVA - 1603 Square Destroyer (DLX可重复覆盖+IDA*)
题目链接 给你一个n*n的由火柴组成的正方形网格,从中预先拿掉一些火柴,问至少还需要拿掉多少火柴才能破坏掉所有的正方形. 看到这道题,我第一反应就是——把每根火柴和它能破坏掉的正方形连边,不就是个裸的 ...
随机推荐
- 学习XOR
//f(x;W,c,w,b)=w*max{0, W*x+c}+b #include <iostream>#include <vector>#include <algori ...
- LA6878
区间dp dp[i][j]存i->j区间的所有取值 然后枚举分割点,枚举两个存的值,分别运算存储. 看见这种不确定分割顺序,两个区间合并的情况,就要用区间dp. #include<bits ...
- Win7系统专栏
1.去掉Win7快捷方式小箭头的方法如下: 使用普通方法会使系统出现异常,比如开始菜单程序无法删除.收藏夹无法展开等,网上流传使用透明图标的方法会在快捷方式上留下一块黑痣,下面的方法是小君研究出来的, ...
- MyEclipse配置https
1.参照CAS配置(1)SSL证书配置文章配置证书. 2.打开myeclipse的Workspace下的.metadata/.me_tcat7/conf/server.xml 打开文件,添加如下代码 ...
- Python简介和基础入门
1.1 Python是什么 相信混迹IT界的很多朋友都知道,Python是近年来最火的一个热点,没有之一.从性质上来讲它和我们熟知的C.java.php等没有什么本质的区别,也是一种开发语言,而且已经 ...
- Android 关于Fragment重叠问题分析和解决
一.问题描述 相信大家在使用Fragment的过程中,肯定碰到过Fragment重叠的问题,重启应用就好了.然而原因是什么呢? 二.原因分析 首先,Android管理Fragment有两种方式,使用a ...
- android指纹识别、拼图游戏、仿MIUI长截屏、bilibili最美创意等源码
Android精选源码 一个动画效果的播放控件,播放,暂停,停止之间的动画 用 RxJava 实现 Android 指纹识别代码 Android仿滴滴打车(滴滴UI)源码 Android高仿哔哩哔哩动 ...
- 努比亚 N1 (Nubia NX541J) 解锁BootLoader 并刷入recovery
本篇教程教你如何傻瓜式解锁BootLoader并刷入recovery 仅限于努比亚 N1 (Nubia NX541J)使用. 首先需要在设置-关于手机 找到版本号 然后手机快速连续点击来启用开发者模式 ...
- Pull-up resistors
1 Introduction Pull-up resistors are very common in microcontrollers or any digital logic device. Wi ...
- jQuery顺序加载图片(初版)
浏览器加载图片区别: IE:同时加载与渲染 其他:加载完之后再渲染 根据这个差异用jQuery做个实例:按顺序加载一组图片,加载完成后提示. <!DOCTYPE html> <htm ...