zju 3209 Dlx解精確覆蓋

題目鏈接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3372

 

題意:給出一個矩形區域和一些固定位置的矩形,問從這些矩形中最少選取多少個可以完全覆蓋整個區域,並且不出現重複覆蓋。

 

把n*m的矩形區域當作n*m列,每一個矩形爲一行,問題即轉化爲從這些行中選擇最少的一部分使每一列被覆蓋且僅覆蓋一次。

 

Code

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define M 1024
#define N 512
const int V=N*M;
const int head=0;

int U[V],D[V],L[V],R[V],C[V];

int S[M],H[M];

int ans,size;

int n,m,p;

void Remove(int c)
{
	int i,j;
	L[R[c]]=L[c],R[L[c]]=R[c];
	for(i=D[c];i!=c;i=D[i]){
		for(j=R[i];j!=i;j=R[j]){
			S[C[j]]--;
			U[D[j]]=U[j];
			D[U[j]]=D[j];
		}
	}
}
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]){
			S[C[j]]++;
			U[D[j]]=D[U[j]]=j;
		}
	}
	L[R[c]]=R[L[c]]=c;
}

void Dance(int k)
{
	int min,i,j,c;

	if(R[head]==head){
		if(k<ans) ans=k;
		return;
	}
	for(min=M,c=0,i=R[head];i!=head;i=R[i]){
		if(S[i]<min) min=S[i],c=i;
	}
	Remove(c);
	for(i=D[c];i!=c;i=D[i]){
		for(j=R[i];j!=i;j=R[j])
			Remove(C[j]);
		Dance(k+1);
		for(j=L[i];j!=i;j=L[j])
			Resume(C[j]);
	}Resume(c);
}

void Link(int &r,int c)
{
	S[c]++;C[size]=c;

	U[size]=U[c];D[U[c]]=size;
	D[size]=c;U[c]=size;
	if(r==-1) 
		L[size]=R[size]=r=size;
	else{
		L[size]=L[r];R[L[r]]=size;
		R[size]=r;L[r]=size;
	}size++;
}

int main()
{

	int t,i,x,y;
	int xo,yo,xl,yl;

	scanf("%d",&t);

	while(t--){
		scanf("%d%d%d",&n,&m,&p);
		m*=n;n=m/n;

		for(i=0;i<=m;i++){
			S[i]=0;U[i]=D[i]=i;
			L[i+1]=i;R[i]=i+1;
		}R[m]=0;size=m+1;
		memset(H,-1,sizeof(H));
		for(i=0;i<p;i++){
			scanf("%d%d%d%d",&xo,&yo,&xl,&yl);
			for(x=xo;x<xl;x++){
				for(y=yo+1;y<=yl;y++)
					Link(H[i],x*n+y);
			}
		}ans=M;
		Dance(0);
		printf("%d\n",ans==M?-1:ans);
	}
	return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章