其他分享
首页 > 其他分享> > 「舞蹈链 DLX 」学习笔记

「舞蹈链 DLX 」学习笔记

作者:互联网




#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int Maxn=5000+500+10;
int n,m,l[Maxn],r[Maxn],u[Maxn],d[Maxn];// 十字链表左右上下
int idx,ansn,ans[Maxn],s[Maxn],row[Maxn],col[Maxn];
void init() // 预处理 
{	
	for(int i=0;i<=m;i++)
	{	
		l[i]=i-1;r[i]=i+1;
		u[i]=d[i]=i; 
	}
	l[0]=m;r[m]=0; // 注意十字链表是收尾相接 
	idx=m+1;
}
void add(int &hd,int &tl,int x,int y) // 十字链表加点 
{	
	row[idx]=x;col[idx]=y;s[y]++;
	u[idx]=y;d[idx]=d[y];u[d[y]]=idx;d[y]=idx;
	r[hd]=l[tl]=idx;r[idx]=tl;l[idx]=hd;
	tl=idx++;
}
void remove(int p) // 删除 
{	
	r[l[p]]=r[p];l[r[p]]=l[p];
	for(int i=d[p];i!=p;i=d[i])
		for(int j=r[i];j!=i;j=r[j])
		{	
			s[col[j]]--;
			u[d[j]]=u[j];d[u[j]]=d[j];
		}
}
void resum(int p) // 复原 
{	
	for(int i=u[p];i!=p;i=u[i])
		for(int j=l[i];j!=i;j=l[j])
		{	
			u[d[j]]=j;d[u[j]]=j;
			s[col[j]]++;
		}
	r[l[p]]=p;l[r[p]]=p;
}
bool dfs()
{	
	if(!r[0])return 1;
	int p=r[0];
	for(int i=r[0];i;i=r[i])
		if(s[i]<s[p])p=i; // 优先选择一行里面 1 多的列。 
	remove(p);
	for(int i=d[p];i!=p;i=d[i])
	{	
		ans[++ansn]=row[i];
		for(int j=r[i];j!=i;j=r[j])remove(col[j]);
		if(dfs())return 1;
		for(int j=l[i];j!=i;j=l[j])resum(col[j]);
		ansn--;
	}
	resum(p);
	return 0;
}
int main()
{	
	scanf("%d%d",&n,&m);
	init();
	for(int i=1;i<=n;i++)
	{	
		int hd=idx,tl=idx;
		for(int j=1;j<=m;j++)
		{	
			int x;
			scanf("%d",&x);
			if(x)add(hd,tl,i,j);
		}
	}
	if(dfs())
		for(int i=1;i<=ansn;i++)
			printf("%d ",ans[i]);
	else printf("No Solution!");
	printf("\n");
	return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int Maxn=10000+5;
int n,m,l[Maxn],r[Maxn],u[Maxn],d[Maxn],s[Maxn];
int idx,tot,ans[Maxn],col[Maxn],row[Maxn];
bool st[Maxn];
void init()
{	
	for(int i=0;i<=m;i++)
	{	
		l[i]=i-1;r[i]=i+1;
		u[i]=d[i]=col[i]=i;
		s[i]=0;
	}
	l[0]=m;r[m]=0;
	idx=m+1;
}
int h() //估价函数 
{	
	int cnt=0;
	memset(st,0,sizeof(st));
	for(int i=r[0];i;i=r[i])
	{	
		if(st[col[i]])continue;
		cnt++;
		st[col[i]]=1;
		for(int j=d[i];j!=i;j=d[j])
			for(int k=r[j];k!=j;k=r[k])
				st[col[k]]=1;
	}
	return cnt;
} 
void add(int &hd,int &tl,int x,int y)
{	
	row[idx]=x;col[idx]=y;s[y]++;
	u[idx]=y;d[idx]=d[y];u[d[y]]=idx;d[y]=idx;
	r[hd]=l[tl]=idx;r[idx]=tl;l[idx]=hd;
	tl=idx++;
}
void remove(int p) // 注意列并不会删除 
{	
	for(int i=d[p];i!=p;i=d[i])
		r[l[i]]=r[i],l[r[i]]=l[i];
}
void resum(int p) // 同上 
{	
	for(int i=u[p];i!=p;i=u[i])
		r[l[i]]=i,l[r[i]]=i;
}
bool dfs(int k)
{	
	if(k+h()-1>tot)return 0;
	if(!r[0])return 1;
	int p=r[0];
	for(int i=r[0];i;i=r[i])
		if(s[p]>s[i])p=i;
	// 注意选完列,p 所在的列并不会删除。 
	for(int i=d[p];i!=p;i=d[i])
	{	
		ans[k]=row[i];
		remove(i);
		for(int j=r[i];j!=i;j=r[j])remove(j);
		if(dfs(k+1))return 1;
		for(int j=l[i];j!=i;j=l[j])resum(j);
		resum(i);
	}
	return 0;
}
int main()
{	
	scanf("%d%d",&n,&m);
	init();
	for(int i=1;i<=n;i++)
	{	
		int hd=idx,tl=idx;
		for(int j=1;j<=m;j++)
		{	
			int x;
			scanf("%d",&x);
			if(x)add(hd,tl,i,j);
		}
	}
	tot=0;
	while(!dfs(1))tot++;
	printf("%d\n",tot);
	for(int i=1;i<=tot;i++)
		printf("%d ",ans[i]);
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int Maxn=20000;
struct node{
	int x,y;
	char c;
}op[Maxn];
int m=16*16*4,l[Maxn],r[Maxn],u[Maxn],d[Maxn];// 十字链表左右上下
int idx,ansn,ans[Maxn],s[Maxn],row[Maxn],col[Maxn];
char c[20][20];
void init() // 预处理 
{	
	for(int i=0;i<=m;i++)
	{	
		l[i]=i-1;r[i]=i+1;s[i]=0;
		u[i]=d[i]=i;
	}
	l[0]=m;r[m]=0;
	idx=m+1;
}
void add(int &hd,int &tl,int x,int y)
{	
	row[idx]=x;col[idx]=y;s[y]++;
	u[idx]=y;d[idx]=d[y];u[d[y]]=idx;d[y]=idx;
	r[hd]=l[tl]=idx;r[idx]=tl;l[idx]=hd;
	tl=idx++;
}
void remove(int p)
{	
	r[l[p]]=r[p];l[r[p]]=l[p];
	for(int i=d[p];i!=p;i=d[i])
		for(int j=r[i];j!=i;j=r[j])
		{	
			s[col[j]]--;
			u[d[j]]=u[j];d[u[j]]=d[j];
		}
}
void resum(int p)
{	
	for(int i=u[p];i!=p;i=u[i])
		for(int j=l[i];j!=i;j=l[j])
		{	
			u[d[j]]=j;d[u[j]]=j;
			s[col[j]]++;
		}
	r[l[p]]=p;l[r[p]]=p;
}
bool dfs()
{	
	if(!r[0])return 1;
	int p=r[0];
	for(int i=r[0];i;i=r[i])
		if(s[i]<s[p])p=i;
	remove(p);
	for(int i=d[p];i!=p;i=d[i])
	{	
		ans[++ansn]=row[i];
		for(int j=r[i];j!=i;j=r[j])remove(col[j]);
		if(dfs())return 1;
		for(int j=l[i];j!=i;j=l[j])resum(col[j]);
		ansn--;
	}
	resum(p);
	return 0;
}
void w()
{	
	memset(r,0,sizeof(r));memset(u,0,sizeof(u));
	memset(l,0,sizeof(l));memset(u,0,sizeof(u));
	memset(s,0,sizeof(s));
	memset(col,0,sizeof(col));
	memset(row,0,sizeof(row));
}
int main()
{	int T,cases=0;
	scanf("%d",&T);
	while(T--)
	{	
		for(int i=0;i<16;i++)
			scanf("%s",c[i]);
		if(cases)printf("\n");
		cases++;
		w();
		init();
		for(int i=0,n=1;i<16;i++)
			for(int j=0;j<16;j++)
			{	
				int a=0,b=15;
				if(c[i][j]!='-')a=b=c[i][j]-'A';
				for(int k=a;k<=b;k++,n++)
				{	
					int hd=idx,tl=idx;
					op[n].x=i;op[n].y=j;op[n].c=k+'A';
					add(hd,tl,n,i*16+j+1);
					add(hd,tl,n,256+i*16+k+1);
					add(hd,tl,n,256*2+j*16+k+1);
					add(hd,tl,n,256*3+(i/4*4+j/4)*16+k+1);
				}
			}
		dfs();
		for(int i=1;i<=ansn;i++)
			c[op[ans[i]].x][op[ans[i]].y]=op[ans[i]].c;
		for(int i=0;i<16;i++)
			printf("%s\n",c[i]);
	}
	return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector> 
#include<algorithm>
using namespace std;
const int Maxn=3600+5;
int T,n,m,l[Maxn],r[Maxn],u[Maxn],d[Maxn],s[Maxn];
int idx,tot,ans[Maxn],col[Maxn],row[Maxn];
bool st[Maxn]; // 1.作为估价函数 2.作为建图 
vector<int> sq[60];
void init()
{	
	for(int i=0;i<=m;i++)
	{	
    	l[i]=i-1;r[i]=i+1;
		u[i]=d[i]=col[i]=i;
		s[i]=0;
	}
	l[0]=m;r[m]=0;
	idx=m+1;
}
int h() //估价函数 
{	
	int cnt=0;
	memset(st,0,sizeof(st));
	for(int i=r[0];i;i=r[i])
	{	
    	if(st[col[i]])continue;
		cnt++;
		st[col[i]]=1;
		for(int j=d[i];j!=i;j=d[j])
			for(int k=r[j];k!=j;k=r[k])
				st[col[k]]=1;
	}
	return cnt;
} 
void add(int &hd,int &tl,int x,int y)
{	
	row[idx]=x;col[idx]=y;s[y]++;
	u[idx]=y;d[idx]=d[y];u[d[y]]=idx;d[y]=idx;
	r[hd]=l[tl]=idx;r[idx]=tl;l[idx]=hd;
	tl=idx++;
}
void remove(int p)
{	
	for(int i=d[p];i!=p;i=d[i])
		r[l[i]]=r[i],l[r[i]]=l[i];
}
void resum(int p)
{	
	for(int i=u[p];i!=p;i=u[i])
		r[l[i]]=i,l[r[i]]=i;
}
bool dfs(int k)
{	
	if(k+h()-1>tot)return 0;
	if(!r[0])return 1;
	int p=r[0];
	for(int i=r[0];i;i=r[i])
		if(s[p]>s[i])p=i;
	for(int i=d[p];i!=p;i=d[i])
	{	
		ans[k]=row[i];
		remove(i);
		for(int j=r[i];j!=i;j=r[j])remove(j);
		if(dfs(k+1))return 1;
		for(int j=l[i];j!=i;j=l[j])resum(j);
		resum(i);
	}
	return 0;
}
int main()
{	
	scanf("%d",&T);
	while(T--)
	{	
		int k;
		scanf("%d%d",&n,&k);
		m=idx=0;
		memset(st,0,sizeof(st));
		memset(col,0,sizeof(col));
		for(int i=1;i<=k;i++)
		{	
			int x;
			scanf("%d",&x);
			st[x]=1;
		}
		for(int len=1;len<=n;len++)
			for(int x=1;x+len-1<=n;x++)
				for(int y=1;y+len-1<=n;y++)
				{
					m++;
					sq[m].clear();
					int dd=n*2+1;//一行过去(横n加上竖n+1)个数
					for(int i=0;i<len;i++) //向一个矩形的 4 边(上下左右)连去 
					{	
						sq[m].push_back((x-1)*dd+y+i); //上 
						sq[m].push_back((x-1)*dd+y+i+dd*len); //下 
						sq[m].push_back((x-1)*dd+y+n+i*dd); //左 
						sq[m].push_back((x-1)*dd+y+n+i*dd+len); //右 
					}
					for(int i=0;i<sq[m].size();i++) //相连的边有一个断了,直接删除所有即可 
						if(st[sq[m][i]]){m--;break;}
				}
		init();
		for(int i=1;i<=n*(n+1)*2;i++) //全部边
			if(!st[i])
			{	
				int hh=idx,tl=idx;
				for(int j=1;j<=m;j++)
					if(find(sq[j].begin(),sq[j].end(),i)!=sq[j].end()) //连边存在 
						add(hh,tl,i,j);
			} 
		tot=0;
		while(!dfs(1))tot++;
		printf("%d\n",tot);
	}
	return 0;
}

\[\text{by Rainy7} \]

标签:include,16,int,矩阵,笔记,舞蹈,Maxn,DLX
来源: https://www.cnblogs.com/Rainy7/p/Dancing-Links-X-note.html