【算法】 poj3740Easy Finding-dancing link

传送门:poj3740


存模板用。
讲解:跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题

代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
#define RI register
#define gc getchar()
#define si isdigit(cp)
using namespace std;
const int N=7000;

int cnt,cur,dir[500],stk[N],top;
int m,n,up[N],dn[N],lf[N],rt[N];
int r[N],c[N];

char cp;
inline int rd()
{
	cp=gc;int x=0;
	for(;!si;cp=gc);
	for(;si;cp=gc) x=x*10+(cp^48);
	return x;
}

inline void init()
{
	RI int i,j,x,pre;
	cnt=n;top=0;
	lf[0]=max(1,n-1);rt[0]=1;
	for(i=1;i<=n;++i){
		dir[i]=up[i]=dn[i]=c[i]=i;
		lf[i]=i-1;rt[i]=i+1;
	}rt[n]=0;
	for(i=1;i<=m;++i){
		for(pre=0,j=1;j<=n;++j) 
		  if((rd())){
		  	 cnt++;r[cnt]=i;c[cnt]=j;
		  	 up[cnt]=dir[j];dn[dir[j]]=cnt;dn[cnt]=j;dir[j]=cnt;
		  	 if(!pre) lf[cnt]=rt[cnt]=cnt;
		  	 else{ lf[cnt]=pre;rt[cnt]=rt[pre];rt[pre]=cnt;}
		  	 pre=cnt;
		  }
	}
}

inline void del(int c)
{
	RI int i,x;lf[rt[c]]=lf[c];rt[lf[c]]=rt[c];
	for(x=dn[c];x!=c;x=dn[x])
		for(i=rt[x];i!=x;i=rt[i])
		 dn[up[i]]=dn[i],up[dn[i]]=up[i];
}

inline void recol(int c)
{
	RI int i,x;rt[lf[c]]=c;lf[rt[c]]=c;
	for(x=dn[c];x!=c;x=dn[x])
	 for(i=rt[x];i!=x;i=rt[i])
	  dn[up[i]]=up[dn[i]]=i;
}

bool dfs()
{
	if(!rt[0]) return true;
	RI int i,j,id=rt[0],x;
	del(id);
    for(x=dn[id];x!=id;x=dn[x]){
    	for(i=rt[x];i!=x;i=rt[i]) del(c[i]);
    	if(dfs()) return true;
    	for(i=rt[x];i!=x;i=rt[i]) recol(c[i]);
    }
    recol(id);
    return false;
}

int main(){
	while(scanf("%d%d",&m,&n)!=EOF){
		init();
	    puts(dfs()?"Yes, I found it":"It is impossible");
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值