HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)
很久以前就看到的一个经典题,一直没做,今天拿来练手。街霸
给n<=25个角色,每个角色有 1 or 2 个版本(可以理解为普通版以及爆发版),每个角色版本可以KO掉若干人。
问最少选多少个角色(每个角色只能选一次),使得可以KO掉其他所有人(包括所有版本)。
典型的DLX。前∑mode[i]列表示被KO的人版本,重复覆盖。后n列表示选了的人,精确覆盖。
即,在精确覆盖满足的前提下,完成重复覆盖,且使所选行最少。
据说这题可以转化成只用一种覆盖,或者是dfs+剪枝。这里就先这样吧。
加了好多注释,方便以后看。
注意的是,dance的时候,要先删除重复覆盖,再删除精确覆盖。。。
2515MS
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <queue>
#include <map>
using namespace std; #define MP make_pair
#define ll long long
#define inf 0x3f3f3f3f #define maxr 88
#define maxn (maxr*maxr)
struct DLX{
int m;// amount of column
int m1,m2;// amount of repeat column and exact column
int L[maxn],R[maxn],U[maxn],D[maxn],cnt;
int row[maxn],col[maxn];
int N[maxr],use[maxr],head[maxr];
void init(int _m){// may need modify this function
m = _m;
memset(head,-1,sizeof(head));
memset(N,0,sizeof(N));
for(int i=0;i<=m;++i){
L[i]=i-1,R[i]=i+1;
U[i]=D[i]=i;
row[i]=0,col[i]=i;
}
L[0]=m,R[m]=0;
cnt=m;
best = inf;
}
void exrm(int c){// remove of exact cover, private
L[R[c]]=L[c],R[L[c]]=R[c];
for(int i=D[c];i!=c;i=D[i])
for(int j=R[i];j!=i;j=R[j])
U[D[j]]=U[j],D[U[j]]=D[j],--N[col[j]];
}
void exres(int c){// resume of exact cover, private
for(int i=U[c];i!=c;i=U[i])
for(int j=L[i];j!=i;j=L[j])
U[D[j]]=D[U[j]]=j,++N[col[j]];
L[R[c]]=R[L[c]]=c;
}
void rm(int x){// remove of repeat cover, private
for(int i=D[x];i!=x;i=D[i])
L[R[i]]=L[i],R[L[i]]=R[i];
}
void res(int x){// resume of repeat cover, private
for(int i=D[x];i!=x;i=D[i])
L[R[i]]=R[L[i]]=i;
}
int low(){// private, sometimes need modify this function
int mi=maxr,idx=0;
for(int i=R[0];i<=m1;i=R[i])if(N[i]<mi&&N[i])mi=N[i],idx=i;
return idx;
}
void link(int r,int c){
++N[c],++cnt;
row[cnt]=r,col[cnt]=c;
U[cnt]=U[c],D[cnt]=c;
U[D[cnt]]=D[U[cnt]]=cnt;
if(head[r]==-1)
head[r]=L[cnt]=R[cnt]=cnt;
else {
L[cnt]=L[head[r]];
R[cnt]=head[r];
L[R[cnt]]=R[L[cnt]]=cnt;
}
}
bool del[maxr];
int cost2(){// lower_bound
int ret=0;
memset(del,false,sizeof(del));
for(int c=R[0];c && c<=m1;c=R[c]){
if(!del[c]){
del[c]=true;
ret++;
for(int i=D[c];i!=c;i=D[i])
for(int j=R[i];j!=i;j=R[j])
del[col[j]]=true;
}
}
return ret;
}
int best;
void dance(int dep,int val){// always need modify this function
if(R[0]==0 || R[0]>m1){
best = min(best, val);
return ;
}
int c=low();
if(c==0)return ;
if(dep+cost2()>=best) return ;
for(int i=D[c];i!=c;i=D[i]){
int r=row[i];
use[dep]=i;
rm(i);
for(int j=R[i];j!=i;j=R[j]) if(col[j]<=m1) rm(j);
for(int j=R[i];j!=i;j=R[j]) if(col[j]>m1) exrm(col[j]);
dance(dep+1,val+1);
for(int j=L[i];j!=i;j=L[j]) if(col[j]>m1) exres(col[j]);
for(int j=L[i];j!=i;j=L[j]) if(col[j]<=m1) res(j);
res(i);
}
}
}dlx; int mode[30];
int sum[30];
vector<pair<int,int> >beat[30][2];
int main(){
int t,ca=0;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d",mode+i);
if(i==0) sum[i] = mode[i];
else sum[i] = sum[i-1]+mode[i];
for(int j=0;j<mode[i];++j){
int k,beatp,beatm;
scanf("%d",&k);
beat[i][j].clear();
for(int kk=0;kk<k;++kk){
scanf("%d%d",&beatp,&beatm);
beat[i][j].push_back(MP(beatp,beatm));
}
}
}
dlx.init(sum[n-1]+n);
dlx.m1 = sum[n-1], dlx.m2 = n;
for(int i=0;i<n;++i){
for(int j=0;j<mode[i];++j){
int row = (i?sum[i-1]:0)+j+1;
dlx.link(row,sum[n-1]+i+1);// exact cover
dlx.link(row,(i?sum[i-1]:0)+1);// repeat cover
if(mode[i]==2) dlx.link(row,(i?sum[i-1]:0)+2);// repeat cover
for(int k=0;k<beat[i][j].size();++k){// repeat cover
pair<int,int>tmp = beat[i][j][k];
int beatp = tmp.first;
int beatm = tmp.second;
int col = (beatp?sum[beatp-1]:0)+beatm+1;
dlx.link(row,col);
}
}
}
dlx.dance(0,0);
printf("Case %d: %d\n",++ca,dlx.best);
}
return 0;
}
HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)的更多相关文章
- HDU 3957 Street Fighter (最小支配集 DLX 重复覆盖+精确覆盖 )
DLX经典题型,被虐惨了…… 建一个2*N行3*N列的矩阵,行代表选择,列代表约束.前2*N列代表每个人的哪种状态,后N列保证每个人至多选一次. 显然对手可以被战胜多次(重复覆盖),每个角色至多选择一 ...
- DLX 舞蹈链 精确覆盖 与 重复覆盖
精确覆盖问题:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 还有重复覆盖问题 dancing links 是 一种数据结构,用来优化搜索,不算是一种算法.(双向 ...
- 【HDOJ】3957 Street Fighter
一定要注意审题啊,题目说的是选出做少的英雄打败其余处在任何模式下的英雄.共有Sigma(num of model)个方案,每个方案有Sigma(num of model)+n个决策.挺不错的一道精确覆 ...
- zoj - 3209 - Treasure Map(精确覆盖DLX)
题意:一个 n x m 的矩形(1 <= n, m <= 30),现给出这个矩形中 p 个(1 <= p <= 500)子矩形的左下角与右下角坐标,问最少用多少个子矩形能够恰好 ...
- hdu 1426 Sudoku Killer ( Dancing Link 精确覆盖 )
利用 Dancing Link 来解数独 详细的能够看 lrj 的训练指南 和 < Dancing Links 在搜索中的应用 >这篇论文 Dancing Link 来求解数独 , ...
- HDU 3111 Sudoku ( Dancing Links 精确覆盖模型 )
推荐两篇学DLX的博文: http://bbs.9ria.com/thread-130295-1-1.html(这篇对DLX的工作过程演示的很详细) http://yzmduncan.iteye.co ...
- HDU 5046 Airport【DLX重复覆盖】
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5046 题意: 给定n个城市的坐标,要在城市中建k个飞机场,使城市距离最近的飞机场的最长距离最小,求这 ...
- HDU 2295.Radar (DLX重复覆盖)
2分答案+DLX判断可行 不使用的估计函数的可重复覆盖的搜索树将十分庞大 #include <iostream> #include <cstring> #include < ...
- [ACM] HDU 2295 Radar (二分法+DLX 重复覆盖)
Radar Problem Description N cities of the Java Kingdom need to be covered by radars for being in a s ...
随机推荐
- 在XP、Win7/8上如何右键进入命令行
在Win7/8上特别简单,只需要在按下shift键后,再点击鼠标右键,即可进入命令行界面.
- R语言学习笔记
向量化的函数 向量化的函数 ifelse/which/where/any/all/cumsum/cumprod/对于矩阵而言,可以使用rowSums/colSums.对于“穷举所有组合问题" ...
- NOIP2010 引水入城 题解
http://www.rqnoj.cn/problem/601 今天发现最小区间覆盖竟然是贪心,不用DP!于是我又找到这题出来撸了一发. 要找到最上面每个城市分别能覆盖最下面哪些城市,如果最下面有城市 ...
- Backbone.js源码分析(珍藏版)
源码分析珍藏,方便下次阅读! // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Backbone ...
- 自执行的匿名函数!function()
最近有空可以让我静下心来看看各种代码,function与感叹号的频繁出现,让我回想起2个月前我回杭州最后参加团队会议的时候,@西子剑影抛出的一样的问题:如果在function之前加上感叹号 (!) 会 ...
- 【bzoj4027】[HEOI2015]兔子与樱花
题目描述 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它 ...
- 部署Apache网站访问统计-AWStats分析系统
环境根据:http://www.cnblogs.com/zzzhfo/p/5925786.html 1.安装AWStats软件包 将软件包解压到httpd服务器中的/usr/lcoal/目录下 [ro ...
- EF接触03
emdx文件解读:
- EasyUI中Dialog的使用
$(function () { $('<div id="dlgContent"></div>').appendTo($('body')); $('#dlgC ...
- 【转】 GridView 72般绝技
说明:准备出一个系列,所谓精髓讲C#语言要点.这个系列没有先后顺序,不过尽量做到精.可能会不断增删整理,本系列最原始出处是csdn博客,谢谢关注. C#精髓 第四讲 GridView 72般绝技 作者 ...