【noi2005】智慧珠游戏

noi2005的题不得不说太重口味了,三道神题(维护数列、智慧珠游戏、月下柠檬树)想AC?那好,交出至少5KB的程序吧,怪不得300+就有金牌了。

 

题目大意很简单,类似于七巧板,你有12种骨牌,其中3联骨牌1个,4联骨牌3个,5联骨牌8个,现在给你个残局,要求你用剩下的骨牌填满棋盘,棋盘是个10*10的三角形。

 

我想应该没有什么牛人用状态压缩DP做出来了吧?那好,这就只能搜索了。

开始是不想做这道题的,但是看到STD如此之慢(GHY一共是要1S+),徒生出虐STD的想法,可能知道的人不多,解决覆盖类问题有一神级算法,叫Dancing Links,专门为‘精确覆盖’设计的超级搜索。

 

首先说说精确覆盖:给你一个0-1矩阵,要你选出一些行,使得这些行的每一列有且仅有一个1。

 

关于DLX可以看相关论文,现在的目的是怎么把它转换为精确覆盖模型。

在这道题中可知有2个覆盖条件:

1.每块骨牌只能用一次,且不能不用;

2.对于每个区域,骨牌不可以重复覆盖,也就是这个区域只能被一块骨牌覆盖,且不能不覆盖;

 

这两个条件都和精确覆盖的条件:每行有且仅有一个1很相似,那么我们就可构造了。

 

列分别为所有没有放骨牌的格子和没有被用到的骨牌,行为每种骨牌的不同放置方案。

 

非常可观的速度:

【noi2005】智慧珠游戏_第1张图片

 

嗯,感觉这个常量表还是打的挺漂亮的。

 program ex3; type fan=array[1..5,1..2] of longint; const len:array[1..12] of longint=(3,4,4,4,5,5,5,5,5,5,5,5); wk:array[1..12] of fan= (((0,0),(1,0),(0,1),(0,0),(0,0)), ((0,0),(1,0),(2,0),(3,0),(0,0)), ((0,0),(1,0),(2,0),(0,1),(0,0)), ((0,0),(1,0),(0,1),(1,1),(0,0)), ((0,0),(1,0),(2,0),(0,1),(0,2)), ((0,0),(1,0),(2,0),(3,0),(1,1)), ((0,0),(1,0),(2,0),(2,1),(0,1)), ((0,0),(1,0),(2,0),(0,1),(1,1)), ((0,0),(1,0),(2,0),(2,1),(3,1)), ((0,0),(1,0),(2,0),(1,1),(1,-1)), ((0,0),(0,1),(1,1),(1,2),(2,2)), ((0,0),(1,0),(2,0),(3,0),(0,1))); var tak:array[0..100] of fan; lv:array[0..20] of boolean; ln:array[0..100] of longint; map,num:array[0..15,0..15] of longint; u,d,l,r,tt,tx,ty,size,h:array[0..100000] of longint; i,j,k,tot,x,y,xx,yy,t,now:longint; p:char; procedure print;var i,j:longint; begin for i:=1 to 10 do begin for j:=1 to i do write(chr(map[i,j]+64)); writeln; end; close(input);close(output);halt; end; procedure rorate(var a,b:fan);var i:longint; begin for i:=1 to 5 do begin b[i,1]:=a[i,2]; b[i,2]:=-a[i,1]; end; end; procedure rev(var a,b:fan);var i:longint; begin for i:=1 to 5 do begin b[i,1]:=a[i,1]; b[i,2]:=-a[i,2]; end; end; function ck(x,y,n:longint):boolean;var i:longint; begin for i:=1 to len[ln[n]] do if map[x+tak[n,i,1],y+tak[n,i,2]]<>0 then exit(false); ck:=true; end; procedure cover(i:longint);var j,k:longint; begin l[r[i]]:=l[i];r[l[i]]:=r[i]; j:=d[i]; while i<>j do begin k:=r[j]; while k<>j do begin u[d[k]]:=u[k];d[u[k]]:=d[k]; dec(size[h[k]]); k:=r[k]; end; j:=d[j]; end; end; procedure recover(i:longint);var j,k:longint; begin l[r[i]]:=i;r[l[i]]:=i; j:=u[i]; while i<>j do begin k:=l[j]; while k<>j do begin u[d[k]]:=k;d[u[k]]:=k; inc(size[h[k]]); k:=l[k]; end; j:=u[j]; end; end; procedure DLX;var i,j,k,min:longint; begin i:=r[0];min:=maxlongint; while i<>0 do begin if size[i]<min then begin min:=size[i];j:=i; end; i:=r[i]; end; if min=maxlongint then print; if min=0 then exit; cover(j); i:=d[j]; while i<>j do begin k:=r[i]; map[tx[i],ty[i]]:=tt[i]; while k<>i do begin cover(h[k]); map[tx[k],ty[k]]:=tt[k]; k:=r[k]; end; DLX; k:=l[i]; map[tx[i],ty[i]]:=0; while k<>i do begin recover(h[k]); map[tx[k],ty[k]]:=0; k:=l[k]; end; i:=d[i]; end; recover(j); end; begin assign(input,'zhzyx.in');reset(input); assign(output,'zhzyx.out');rewrite(output); fillchar(map,sizeof(map),$ff); for i:=1 to 10 do begin for j:=1 to i do begin read(p); map[i,j]:=0; if p in ['A'..'Z'] then begin map[i,j]:=ord(p)-64; lv[map[i,j]]:=true; end; if map[i,j]=0 then begin inc(tot);num[i,j]:=tot; l[tot]:=tot-1;r[tot-1]:=tot; u[tot]:=tot;d[tot]:=tot;h[tot]:=tot; end; end;readln end; for i:=1 to 12 do if not lv[i] then begin inc(tot); num[i,0]:=tot; l[tot]:=tot-1;r[tot-1]:=tot; u[tot]:=tot;d[tot]:=tot;h[tot]:=tot; inc(t);ln[t]:=i;tak[t]:=wk[i]; if (i=4) or (i=10) then continue; inc(t);rorate(tak[t-1],tak[t]);ln[t]:=i; if i=2 then continue; inc(t);rorate(tak[t-1],tak[t]);ln[t]:=i; inc(t);rorate(tak[t-1],tak[t]);ln[t]:=i; if (i=10) or (i=7) or (i=5) or (i=1) then continue; inc(t);rev(tak[t-1],tak[t]);ln[t]:=i; inc(t);rorate(tak[t-1],tak[t]);ln[t]:=i; inc(t);rorate(tak[t-1],tak[t]);ln[t]:=i; inc(t);rorate(tak[t-1],tak[t]);ln[t]:=i; end; l[0]:=tot; for i:=1 to t do for x:=1 to 10 do for y:=1 to x do if ck(x,y,i) then begin inc(tot);l[tot]:=tot;r[tot]:=tot; u[tot]:=u[num[ln[i],0]];d[tot]:=h[u[tot]]; d[u[tot]]:=tot;u[d[tot]]:=tot; now:=tot;h[now]:=h[u[now]]; inc(size[h[tot]]); for j:=1 to len[ln[i]] do begin xx:=x+tak[i,j,1];yy:=y+tak[i,j,2]; inc(tot);l[tot]:=now;r[tot]:=r[now]; now:=tot;h[tot]:=num[xx,yy]; d[tot]:=h[tot];u[tot]:=u[h[tot]]; l[r[tot]]:=tot;r[l[tot]]:=tot; d[u[tot]]:=tot;u[d[tot]]:=tot; inc(size[h[tot]]); tx[tot]:=xx;ty[tot]:=yy;tt[tot]:=ln[i]; end; end; DLX; writeln('No solution'); close(input);close(output); end.

 

你可能感兴趣的:(游戏,算法,input,output)