神龙的难题 FZU - 1686

2 篇文章 0 订阅

//刚开始TLE了...然后改成启发式搜索(必须<=,只有<也会TLE)WA了

区别可能是AC代码只需要在找到选择一行的时候,只删去这一行上所有点的列

WA代码的删除部分则是//删去所有与当前行中1相互矛盾的行即for循环删去该行j列中所有1的行(除了num本身)

AC代码:

#include <iostream>
#include <cstdio>
#include<cstring>

using namespace std;

const int maxm=15*15+5;//最大列数
const int maxn=15*15+5;//最大行数
const int maxnode=maxm*maxn;//最大节点数

const int inf = 0x3f3f3f3f;

class dlx {
	public:
		int n,m,size;

		int R[maxnode],L[maxnode],U[maxnode],D[maxnode],col[maxnode],H[maxn],row[maxnode],S[maxm];

		//表示最后选中的行的数量,ans记录答案
		int res,ans[maxn];

		void init(int x,int y) {
			n=x;
			m=y;
			res = inf;
			int i;

			for(i=0; i<=m; i++) {
				S[i]=0;
				U[i]=i;
				D[i]=i;
				L[i]=i-1;
				R[i]=i+1;
			}
			L[0]=m;
			R[m]=0;

			size=m;

			for(i=0; i<=n; i++) {
				H[i]=-1;
			}
		}

		void link(int r,int c) {
			size++;
			col[size]=c;
			row[size]=r;

			S[col[size]]++;


			U[size]=c;
			D[size]=D[c];
			U[D[c]]=size;
			D[c]=size;

			if(H[r]<0) {
				H[r]=L[size]=R[size]=size;
			} else {
				R[size]=R[H[r]];
				L[size]=H[r];
				L[R[H[r]]]=size;
				R[H[r]]=size;
			}
		}

		void remove(int c) {
			for(int i = D[c]; i != c; i = D[i]) {
				L[R[i]] = L[i];
				R[L[i]] = R[i];
			}

		}

		void resume(int c) {
			for(int i = U[c]; i != c; i = U[i]) {
				L[R[i]] = R[L[i]] = i;
			}
		}
		bool v[maxn];
		int f() {
			int h = 0;
			for(int c = R[0]; c != 0; c = R[c])
				v[c] = true;
			for(int c = R[0]; c != 0; c = R[c]) {
				if(v[c]) {
					h ++;
					v[c] = false;
					for(int i = D[c]; i != c; i = D[i])  {
						for(int j = R[i]; j != i; j = R[j])
							v[col[j]] = false;
					}
				}
			}
			return h;
		}


		void dance(int cnt) {
			if(cnt+f() >= res) return;//A*
			//当原点的右边结点是自己时,所有的已经全部删除完毕,符合条件
			if(R[0]==0) {
				res=min(res, cnt);

				return;
			}
			int cur;
			cur=R[0];
			for(int i=cur; i!=0; i=R[i]) {
				if(S[cur]>S[i]) {
					cur=i;
				}
			}
			int i,j;

			for(i=D[cur]; i!=cur; i=D[i]) {//只删去这一行上所有点的列
				remove(i);

				for(j=R[i]; j!=i; j=R[j]) {
					remove(j);
				}
				dance(cnt+1);

				for(j=L[i]; j!=i; j=L[j]) {
					resume(j);
				}
				resume(i);
			}
			return;
		}
};

dlx g;

int a[20][20];
int id[20][20];

int main() {
	int n, m;

	while(~scanf("%d%d",&n,&m)) {
		int sz = 0;

		memset(id,0,sizeof(id));

		for(int i = 0; i < n; i ++) {
			for(int j = 0; j < m; j ++) {
				scanf("%d", &a[i][j]);

				if(a[i][j] == 1) id[i][j] = (++sz);
			}
		}

		g.init(n * m, sz);

		sz = 1;

		int n1, m1;

		scanf("%d%d", &n1, &m1);

		for(int i = 0; i < n; i ++) {
			for(int j = 0; j < m; j ++) {
				for(int x = 0; x < n1 && i + x < n; x ++) {
					for(int y = 0; y < m1 && j + y < m; y ++) {
						if(id[i + x][j + y])
							g.link(sz,id[i + x][j + y]);
					}
				}
				sz ++;
			}
		}
		g.dance(0);

		printf("%d\n", g.res);
	}
	return 0;

}

//WA代码

#include <iostream>
#include <cstdio>
#include<cstring>

using namespace std;

const int maxm=15*15+5;//最大列数
const int maxn=15*15+5;//最大行数
const int maxnode=maxm*maxn;//最大节点数

const int inf = 0x3f3f3f3f;

class dlx {
	public:
		int n,m,size;

		int R[maxnode],L[maxnode],U[maxnode],D[maxnode],col[maxnode],H[maxn],row[maxnode],S[maxm];

		//表示最后选中的行的数量,ans记录答案
		int res,ans[maxn];

		void init(int x,int y) {
			n=x;
			m=y;
			res = inf;
			int i;

			for(i=0; i<=m; i++) {
				S[i]=0;
				U[i]=i;
				D[i]=i;
				L[i]=i-1;
				R[i]=i+1;
			}
			L[0]=m;
			R[m]=0;

			size=m;

			for(i=0; i<=n; i++) {
				H[i]=-1;
			}
		}

		void link(int r,int c) {
			size++;
			col[size]=c;
			row[size]=r;

			S[col[size]]++;


			U[size]=c;
			D[size]=D[c];
			U[D[c]]=size;
			D[c]=size;

			if(H[r]<0) {
				H[r]=L[size]=R[size]=size;
			} else {
				R[size]=R[H[r]];
				L[size]=H[r];
				L[R[H[r]]]=size;
				R[H[r]]=size;
			}
		}

		void remove(int c) {
			R[L[c]]=R[c];
			L[R[c]]=L[c];
			int x,y;
			for(x=D[c]; x!=c; x=D[x]) {
				for(y=R[x]; y!=x; y=R[y]) {
					D[U[y]]=D[y];
					U[D[y]]=U[y];
					S[col[y]]--;
				}
			}
		}

		void resume(int c) {
			int i,j;
			for(i=U[c]; i!=c; i=U[i]) {
				for(j=L[i]; j!=i; j=L[j]) {
					U[D[j]]=j;
					D[U[j]]=j;
					S[col[j]]++;
				}
			}
			L[R[c]]=R[L[c]]=c;
		}
		bool v[maxn];
		int f() { 
			int h = 0;
			for(int c = R[0]; c != 0; c = R[c]) 
				v[c] = true;
			for(int c = R[0]; c != 0; c = R[c]){
				if(v[c]){
					h ++;
					v[c] = false;
					for(int i = D[c]; i != c; i = D[i])  {
						for(int j = R[i]; j != i; j = R[j])
							v[col[j]] = false;
					}
				}
			}
			return h;
		}


		void dance(int cnt) 
		{
			if(cnt+f() >= res) return;//A*
			//当原点的右边结点是自己时,所有的已经全部删除完毕,符合条件
			if(R[0]==0) {
				res=min(res, cnt);

				return;
			}
			int cur;

			cur=R[0];

			for(int i=cur; i!=0; i=R[i]) {
				if(S[cur]>S[i]) {
					cur=i;
				}
			}
			remove(cur);
			int i, j;

			for(i=D[cur]; i!=cur; i=D[i]) {
				for(j=R[i]; j!=i; j=R[j]) {
					remove(col[j]);
				}

				dance(cnt+1);

				for(j=L[i]; j!=i; j=L[j]) {
					resume(col[j]);
				}
			}
			resume(cur);
			return;
		}
};

dlx g;

int a[20][20];
int id[20][20];

int main() {
	int n, m;

	while(~scanf("%d%d",&n,&m)) {
		int sz = 0;

		memset(id,0,sizeof(id));

		for(int i = 0; i < n; i ++) {
			for(int j = 0; j < m; j ++) {
				scanf("%d", &a[i][j]);

				if(a[i][j] == 1) id[i][j] = ++sz;
			}
		}

		g.init(n * m,sz);

		sz = 1;

		int n1, m1;

		scanf("%d%d", &n1, &m1);

		for(int i = 0; i < n; i ++) {
			for(int j = 0; j < m; j ++) {
				for(int x = 0; x < n1 && i + x < n; x ++) {
					for(int y = 0; y < m1 && j + y < m; y ++) {
						if(id[i + x][j + y])
							g.link(sz,id[i + x][j + y]);
					}
				}
				sz ++;
			}
		}
		g.dance(0);

		printf("%d\n", g.res);
	}
	return 0;

}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值