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;
}
时间: 2024-10-25 16:11:26

HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)的相关文章

最新版dlx模板(精确覆盖+重复覆盖)

以前的代码太挫了,重新整理dlx,学习HH把精确覆盖,重复覆盖整合在一起. 代码: struct DLX{ const static int maxn=20010; #define FF(i,A,s) for(int i = A[s];i != s;i = A[i]) int L[maxn],R[maxn],U[maxn],D[maxn]; int size,col[maxn],row[maxn],s[maxn],H[maxn]; bool vis[70]; int ans[maxn],cnt;

【HDOJ】3957 Street Fighter

一定要注意审题啊,题目说的是选出做少的英雄打败其余处在任何模式下的英雄.共有Sigma(num of model)个方案,每个方案有Sigma(num of model)+n个决策.挺不错的一道精确覆盖的题目,最近发现精确覆盖很有意思. 1 /* 3957 */ 2 #include <iostream> 3 #include <string> 4 #include <map> 5 #include <queue> 6 #include <set>

hdu 1426 Sudoku Killer ( Dancing Link 精确覆盖 )

利用 Dancing Link 来解数独 具体的可以看    lrj 的训练指南 和 < Dancing Links 在搜索中的应用 >这篇论文 Dancing Link 来求解数独 , 是通过求解精确覆盖 精确覆盖就是给出一个 01 矩阵 , 要求我们选择一些行 , 使得每一列有且仅有一个 1 对于数独问题 , 行就是我们的选择 , 即在第 i 行 第 j 列 放上 数字 k , 所以我们最多有 i * j * k 中选择 如果某些位置( x , y  )已经放了数字 a , 那么我们的选择

zoj - 3209 - Treasure Map(精确覆盖DLX)

题意:一个 n x m 的矩形(1 <= n, m <= 30),现给出这个矩形中 p 个(1 <= p <= 500)子矩形的左下角与右下角坐标,问最少用多少个子矩形可以恰好组成这个 n x m 的大矩形. 题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3372 -->>这是精确覆盖问题,而DLX正是解决精确覆盖问题的有利武器.. 模型转换:将原矩形变成一行,作为 DLX 中的列,表示要

HDU 5046 Airport(DLX重复覆盖)

HDU 5046 Airport 题目链接 题意:给定一些机场,要求选出K个机场,使得其他机场到其他机场的最大值最小 思路:二分+DLX重复覆盖去判断即可 代码: #include <cstdio> #include <cstring> using namespace std; const int MAXNODE = 4005; const int MAXM = 65; const int MAXN = 65; const int INF = 0x3f3f3f3f; int K;

[DLX重复覆盖] hdu 2828 Lamp

题意: 有N个灯M个开关 每个灯的ON和OFF状态都能控制一个灯是否亮 给出N行,代表对于每个灯 哪些开关的哪个状态可以使得第i个灯亮 思路: 这里需要注意一个问题 如果开关1的ON 状态和开关2的ON状态能使得1号灯亮 那么开关1.2同时处于ON的时候 1号灯也是亮的.意思就是只要有一个开关使得灯亮,灯就亮了. 简单的DLX 重复覆盖 行为每个开关的两个状态2*m行,列为n个灯 在搜索的同时标记一下哪个开关被用过了 那么另一个状态也不能用了 代码: #include"stdio.h"

HDU 2295.Radar (DLX重复覆盖)

2分答案+DLX判断可行 不使用的估计函数的可重复覆盖的搜索树将十分庞大 #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <vector> using namespace std; #define FOR(i,A,s) for(int i = A[s]; i != s; i = A[i]) #define exp 1e-8 con

[ACM] HDU 2295 Radar (二分+DLX 重复覆盖)

Radar Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2593    Accepted Submission(s): 1012 Problem Description N cities of the Java Kingdom need to be covered by radars for being in a state of

DLX精确覆盖与重复覆盖模板题

hihoCoder #1317 : 搜索四·跳舞链 原题地址:http://hihocoder.com/problemset/problem/1317 时间限制:10000ms 单点时限:1000ms 内存限制:256MB   描述 小Ho最近遇到一个难题,他需要破解一个棋局. 棋局分成了n行,m列,每行有若干个棋子.小Ho需要从中选择若干行使得每一列有且恰好只有一个棋子. 比如下面这样局面: 其中1表示放置有棋子的格子,0表示没有放置棋子. 对于上面这个问题,小Ho经过多次尝试以后得到了解为选