1. 程式人生 > >UVA 1603 Square Destroyer

UVA 1603 Square Destroyer

space 意義 figure pair reg second res 圖片 判斷

https://vjudge.net/problem/UVA-1603

題目

The left figure below shows a complete$3 \times 3$grid made with2$ \times(3 \times 4)$(=24) matchsticks. The lengthsof all matchsticks are one. You can find many squares of different sizes in the grid. The size of a squareis the length of its side. In the grid shown in the left figure, there are 9 squares of size one, 4 squaresof size two, and 1 square of size three.Each matchstick of the complete grid is identified with a unique number which is assigned from leftto right and from top to bottom as shown in the left figure. If you take some matchsticks out from thecomplete grid, then some squares in the grid will be destroyed, which results in an incomplete $3\times 3$ grid. The right figure illustrates an incomplete $3\times 3$ grid after removing three matchsticks numberedwith 12, 17 and 23. This removal destroys 5 squares of size one, 3 squares of size two, and 1 square of size three. Consequently, the incomplete grid does not have squares of size three, but still has 4 squaresof size one and 1 square of size two.

As input, you are given a (complete or incomplete) $n \times n$ grid made with no more than $2n(n + 1)$ matchsticks for a natural number $n \leqslant 5$. Your task is to compute the minimum number of matchsticks taken out to destroy all the squares existing in the input $n \times n$ grid.

技術分享圖片

題解

做這個題做到自閉……

首先判斷正方形的部分就不好寫(寫了3小時)……然後搜索的復雜度也猜不出來,狀態數高達$2 ^ {220}$,BFS存不下狀態

換用叠代加深搜,一直TLE

TLE代碼

#include<bits/stdc++.h>
using namespace std;
#define REP(i,x,y) for(register int i=(x); i<(y); i++)
#define REPE(i,x,y) for(register int i=(x); i<=(y); i++)
#define MAXN 30
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__);
#else
#define DBG(...)
#endif
typedef pair<int,int> pii;
bool arr[220];
int md;
int n,tot;
int counter(bool *arr, pii *stick) {
	int s=0;
	bool k=true;
	k=true;
	REPE(sz,1,n) {
		REPE(ax,0,n-sz) REPE(ay,0,n-sz) {
			k=true;
			REP(i,0,sz) {
				if(arr[ax+ay*(n+n+1)+i]) {
					k=false;
					break;
				}
			}
			if(k)REP(i,0,sz) {
				if(arr[ax+(ay+i)*(n+n+1)+n] || arr[ax+(ay+i)*(n+n+1)+n+sz]) {
					k=false;
					break;
				}
			}
			if(k)REP(i,0,sz) {
				if(arr[ax+(ay+sz)*(n+n+1)+i]) {
					k=false;
					break;
				}
			}
			if(k){
				s++;
				REPE(bx,0,n-sz) REPE(by,0,n-sz) {
					REP(i,0,sz) {
						stick[bx+by*(n+n+1)+i].first++;
					}
					REP(i,0,sz) {
						stick[bx+(by+i)*(n+n+1)+n].first++;
						stick[bx+(by+i)*(n+n+1)+n+sz].first++;
					}
					REP(i,0,sz) {
						stick[bx+(by+sz)*(n+n+1)+i].first++;
					}
				}
			}
		}
		
	}
	return s;
}
bool solve(int d, bool *oarr) {
	pii stick[220];
	REP(i,0,tot) stick[i].second=i,stick[i].first=0;
	int s=counter(oarr,stick);
	if(s==0) return true;
	sort(stick,stick+tot,greater<pii>());
	
	if(stick[0].first==1) {
		md+=s;
		return true;
	}
	int sum=0, k=999999;
	REP(i,0,tot) {
		sum+=stick[i].first;
		if(sum>=s) {k=i+1; break;}
	}
	if(k+d>md) return false;
	REP(i,0,tot) {
		if(oarr[stick[i].second]) continue;
		oarr[stick[i].second]=1;
		if(solve(d+1,oarr)) return true;
		oarr[stick[i].second]=0;
	}
	return 0;
}
int main() {
#ifdef sahdsg
	freopen("in.txt", "r", stdin);
#endif
	int T;
	scanf("%d",&T);
	while(0<T--) {
		scanf("%d",&n);
		tot=2*n*(n+1);
		int d;
		scanf("%d",&d);
		memset(arr,0,sizeof arr);
		REP(i,0,d) {
			int t;
			scanf("%d",&t);
			arr[t]=1;
		}
		for(md=0; ; md++) {
			DBG("#%d", md);
			if(solve(0,arr)) {
				printf("%d\n", md);
				break;
			}
		}
	}
	return 0;
}

看了答案 最重要的判斷正方形的部分太慢了……

需要預處理,對每個正方形編號,然後保存每個完整正方形的火柴數目,然後維護正方形的實時火柴棍數目,或者使用DLX算法

(今天去聽大學的意義的講座,也是服了,為什麽要浪費人參啊……)

UVA 1603 Square Destroyer