3740 - Easy Finding

精确覆盖(dancing link)的板子题。

参考了下面的博客:

这个博客虽然不是用c++写的代码,但讲的十分详细,有助于理解。http://www.cnblogs.com/grenet/p/3145800.html

又短又漂亮的c++代码,值得一膜:http://blog.csdn.net/xianxingwuguan1/article/details/18994601

下面是我的代码(实际上长得和上面那个博客里的一膜一样


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define ll long long
#define db double
#define mkp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define X first
#define Y second
const int N=20,M=305,NM=7000;
int n,m;
struct DLX{
	int L[NM],R[NM],U[NM],D[NM]/*,ro[NM]*/,co[NM],H[N],S[M]/*,cnt*/,sz/*,ans[N]*/;//H为行首,S为每列元素个数 
	void reset(){
		int i;rep(i,0,m)
			S[i]=0,L[i]=i-1,R[i]=i+1,U[i]=D[i]=i;
		L[0]=m,R[m]=0,sz=m+1;
		memset(H,-1,sizeof H);
	}
	void ins(int x,int y){
		++S[co[sz]=y]/*,ro[sz]=x*/;//确定所在行、列 
		U[D[sz]=D[y]]=sz;
		U[D[y]=sz]=y;//将sz插入y和D[y]中
		if(H[x]<0)H[x]=L[sz]=R[sz]=sz;
		else{
			L[R[sz]=R[H[x]]]=sz;
			R[L[sz]=H[x]]=sz;
		}//将sz插入H[x]和R[H[x]]中
		++sz; 
	}
	void del(int c){
		R[L[R[c]]=L[c]]=R[c];
		int i,j;
		for(i=D[c];i!=c;i=D[i])
			for(j=R[i];j!=i;j=R[j])
				D[U[D[j]]=U[j]]=D[j],--S[co[j]];
	}
	void add(int c){
		R[L[c]]=L[R[c]]=c;
		int i,j;
		for(i=U[c];i!=c;i=U[i])
			for(j=L[i];j!=i;j=L[j])
				++S[co[U[D[j]]=D[U[j]]=j]];
	}
	bool DFS(/*int k*/){
		if(!R[0]){
			/*cnt=k;*/return 1;
		} 
		int c,i,j;
		for(i=c=R[0];i;i=R[i])if(S[c]>S[i])c=i;//找出元素最多的一列 
		del(c);
		for(i=D[c];i!=c;i=D[i]){
			for(j=R[i];j!=i;j=R[j])del(co[j]);
//			ans[k]=ro[i]; 
			if(DFS(/*k+1*/))return 1;
			for(j=L[i];j!=i;j=L[j])add(co[j]);
		}
		add(c);
		return 0;
	}
}dlx;
int main(){
	int i,j,x;
	while(~scanf("%d%d",&n,&m)){
		dlx.reset();
		rep(i,1,n)rep(j,1,m){
			scanf("%d",&x);
			if(x)dlx.ins(i,j);
		}
		puts(dlx.DFS(/*0*/)?"Yes, I found it":"It is impossible");
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值