DLX hdu3111 hdu 3909 hdu3663 hdu3957

//http://sqybi.com/works/dlxcn/
/*
同时有部分覆盖与完全覆盖时,尝试取某一行时,一定要先去掉部分覆盖的列,再去完全覆盖的列。
因为去完全覆盖的列时,会把部分覆盖的列的关系打乱,使后面再去部分覆盖时找不到了,无法结束。

hdu3957每个角色最多有两个身份,给出每个角色的身份的胜败关系,选出最少的角色的某个身份,
使得无论其它角色选择什么身份,至少有一个你选的角色打败它。
*/
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

const int maxr=55;
const int maxc=110;
const int maxn=11000;
int L[maxn],R[maxn],U[maxn],D[maxn],RH[maxn],CH[maxn],ynum[maxc];
int sum,r,c,size,head;
bool mat[maxr][maxc],vis[maxc];

int AddNode(int l,int r,int u,int d)
{
	L[size]=l,R[size]=r,U[size]=u,D[size]=d;
	L[r]=R[l]=U[d]=D[u]=size;
	return size++;
}
void Make()
{
	int i,j,k;
	memset(ynum,0,sizeof(ynum));
	size=0;
	head=AddNode(size,size,size,size);
	for(i=0;i<c;i++)
	{
		CH[i+1]=i;
		AddNode(L[head],head,size,size);
	}
	for(i=0;i<r;i++)
		for(k=-1,j=0;j<c;j++)
		{
			if(!mat[i][j]) continue;
			RH[size]=i,CH[size]=j,ynum[j]++;
			if(k==-1)
				k=AddNode(size,size,U[j+1],j+1);
			else k=AddNode(k,R[k],U[j+1],j+1);
		}
	for(i=0;i<c;i++)
		if(!ynum[i])
			L[R[i+1]]=L[i+1],R[L[i+1]]=R[i+1];
}
void Remove(int c)//完全覆盖的去除c列元素的行
{
	L[R[c]]=L[c],R[L[c]]=R[c];
	int i,j,k;
	for(i=U[c];i!=c;i=U[i])
		for(j=R[i];j!=i;j=R[j])
			ynum[CH[j]]--,U[D[j]]=U[j],D[U[j]]=D[j];
}
void Resume(int c)
{
	int i,j,k;
	for(i=D[c];i!=c;i=D[i])
		for(j=L[i];j!=i;j=L[j])
			ynum[CH[j]]++,U[D[j]]=D[U[j]]=j;
	L[R[c]]=R[L[c]]=c;
}
void Remove1(int c)//部分覆盖去除c列
{
	int i;
	for(i=U[c];i!=c;i=U[i])
		L[R[i]]=L[i],R[L[i]]=R[i];
}
void Resume1(int c)
{
	int i;
	for(i=D[c];i!=c;i=D[i])
		L[R[i]]=R[L[i]]=i;
}
int h()
{
	int i,j,k,num=0;
	memset(vis,false,sizeof(vis));
	for(i=R[head];i!=head&&i<=r;i=R[i])
		if(!vis[CH[i]])
		{
			num++;
			vis[CH[i]]=true;
			for(j=U[i];j!=i;j=U[j])
				for(k=R[j];k!=j;k=R[k])
					vis[CH[k]]=true;
		}
	return num;
}
void DFS(int t)
{
	if(t+h()>=sum) return;//部分覆盖的IDA*
	if(R[head]==head||R[head]>r)
	{
		if(sum>t) sum=t;
		return;
	}

	int i,j,k;
	for(k=-1,i=R[head];i!=head&&i<=r;i=R[i])
		if(k==-1||ynum[CH[i]]<ynum[CH[k]])
			k=i;

	//printf("%d %d\n",t,k);
	for(i=U[k];i!=k;i=U[i])
	{
		Remove1(i);//先去掉部分覆盖的
		for(j=R[i];j!=i;j=R[j])
			if(CH[j]<r) Remove1(j);
		for(j=R[i];j!=i;j=R[j])//再去完全覆盖
		{
			if(CH[j]>=r) Remove(CH[j]+1);
		//	else Remove1(j); //混着写是错的,无法正常结束
		}
		
		DFS(t+1);

		for(j=L[i];j!=i;j=L[j])
		{
			if(CH[j]>=r) Resume(CH[j]+1);
		//	else Resume1(j);
		}
		for(j=L[i];j!=i;j=L[j])
			if(CH[j]<r) Resume1(j);	
		Resume1(i);
	}
}
int main()
{
	int t,test=1,n,i,j,k,kk,u,v;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		memset(mat,false,sizeof(mat));
		for(i=0;i<n;i++)
		{
			scanf("%d",&k);
			for(j=0;j<k;j++)
			{
				if(k==2)
					mat[i*2+j][i*2+(j^1)]=true;
				mat[i*2+j][i*2+j]=true;
				mat[i*2+j][n*2+i]=true;
				scanf("%d",&kk);
				while(kk--)
				{
					scanf("%d%d",&u,&v);
					mat[i*2+j][u*2+v]=true;
				}
			}
		}
		r=n*2,c=n*3;
		Make();
		sum=r;
		DFS(0);
		printf("Case %d: %d\n",test++,sum);
	}
	return 0;
}
//hdu3111求9*9的数独
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;

const int maxr=1100;
const int maxc=410;
const int maxn=maxr*maxc;
int o[maxn],L[maxn],R[maxn],U[maxn],D[maxn],RH[maxn],CH[maxn],ynum[maxc];
int size,head,r,c,g[10][10];
bool mat[maxr][maxc];

int AddNode(int l,int r,int u,int d)
{
	L[size]=l,R[size]=r,U[size]=u,D[size]=d;
	L[r]=R[l]=U[d]=D[u]=size;
	return size++;
}

void Remove(int c)//删除c列
{
	L[R[c]]=L[c],R[L[c]]=R[c];
	int i,j;
	for(i=U[c];i!=c;i=U[i])
		for(j=R[i];j!=i;j=R[j])
			D[U[j]]=D[j],U[D[j]]=U[j];
}
void Resume(int c)//恢复c列
{
	int i,j;
	for(i=D[c];i!=c;i=D[i])
		for(j=L[i];j!=i;j=L[j])
			D[U[j]]=U[D[j]]=j;
	L[R[c]]=R[L[c]]=c;
}

bool DFS(int kk)
{
	if(R[head]==head) return true;

	int i,j,k;
	for(k=-1,i=R[head];i!=head;i=R[i])//找含最少元素的列
		if(k==-1||ynum[CH[i]]<ynum[CH[k]])
			k=i;

	Remove(k);
	for(i=U[k];i!=k;i=U[i])//枚举这列元素所在的行
	{
		o[kk]=RH[i];
		for(j=R[i];j!=i;j=R[j])
			Remove(CH[j]+1);
		if(DFS(kk+1)) return true;
		for(j=L[i];j!=i;j=L[j])
			Resume(CH[j]+1);
	}
	Resume(k);
	return false;
}

void Make()
{
	int i,j,k;
	memset(mat,false,sizeof(mat));
	for(i=0;i<9;i++)
		for(j=0;j<9;j++)
			for(k=1;k<=9;k++)
				if(!g[i][j]||g[i][j]==k)
				{
					mat[i*9*9+j*9+k-1][i*9+j]=true;
					mat[i*9*9+j*9+k-1][9*9+i*9+k-1]=true;
					mat[i*9*9+j*9+k-1][2*9*9+j*9+k-1]=true;
					mat[i*9*9+j*9+k-1][3*9*9+(i/3*3+j/3)*9+k-1]=true;
				}

	r=9*9*9;
	c=4*9*9;
	size=0,head=0;
	memset(ynum,0,sizeof(ynum));
	AddNode(size,size,size,size);
	for(i=0;i<c;i++)
	{
		CH[size]=i;
		AddNode(L[head],head,size,size);
	}
	for(i=0;i<r;i++)
		for(k=-1,j=0;j<c;j++)
		{
			if(!mat[i][j]) continue;
			RH[size]=i,CH[size]=j,ynum[j]++;
			if(k==-1)
				k=AddNode(size,size,U[j+1],j+1);
			else k=AddNode(k,R[k],U[j+1],j+1);
		}
}
int main()
{
	int t,i,j;
	char ch[110];
	scanf("%d",&t);
	getchar();
	while(t--)
	{
		for(i=0;i<9;i++)
		{
			gets(ch);
			for(j=0;j<9;j++)
			{
				if(ch[j]=='?') g[i][j]=0;
				else g[i][j]=ch[j]-'0';
			}		
		}
		Make();
		if(!DFS(0))
			printf("impossible\n");
		else
		{
			sort(o,o+81);
			for(i=0;i<81;i++)
			{
				printf("%d",o[i]%9+1);
				if(i%9==8) printf("\n");
			}
		}
		if(t) 
		{
			printf("---\n");
			gets(ch);
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值