1675: [Usaco2005 Feb]Rigging the Bovine Election 竞选划区(题解第二弹)
1675: [Usaco2005 Feb]Rigging the Bovine Election 竞选划区
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 198 Solved: 118
[Submit][Status][Discuss]
Description
It's election time. The farm is partitioned into a 5x5 grid of cow locations, each of which holds either a Holstein ('H') or Jersey ('J') cow. The Jerseys want to create a voting district of 7 contiguous (vertically or horizontally) cow locations such that the Jerseys outnumber the Holsteins. How many ways can this be done for the supplied grid?
农场被划分为5x5的格子,每个格子中都有一头奶牛,并且只有荷斯坦(标记为H)和杰尔西(标记为J)两个品种.如果一头奶牛在另一头上下左右四个格子中的任一格里,我们说它们相连. 奶牛要大选了.现在有一只杰尔西奶牛们想选择7头相连的奶牛,划成一个竞选区,使得其中它们品种的奶牛比荷斯坦的多. 要求你编写一个程序求出方案总数.
Input
* Lines 1..5: Each of the five lines contains five characters per line, each 'H' or 'J'. No spaces are present.
Output
* Line 1: The number of distinct districts of 7 connected cows such that the Jerseys outnumber the Holsteins in the district.
Sample Input
JHJHJ
HHHHH
HJHHJ
HHHHH
Sample Output
HINT
Source
题解:之前的题解中(传送门),采用的是\(O\left({25}^{7} \right)\)的简单暴力枚举,虽然能A,我一直认为还有更灵活的办法可以去做,于是有了这个第二篇题解
这次的思路是:每次先找一个点,然后向这个点的四周进行扩张,每一层dfs在原有的块的基础上再向外扩张一个,最终形成的块必然是7个连续的格子,应该能够起到比较好的优化效果——因为我每次选取扩张的点,都是通过动态维护当前块周围一圈的点来进行的,对于联通块而言,在地图内最多只能有15个周围的点,所以复杂度一下子降到了\(O\left({15}^{7} \right)\),并且完全不需要判断7个点是否构成一块。。。
以上是优点,但是这样一来仔细想想,缺点也十分明显——由于对于同样一个图形而言,可以由很多中扩张顺序可以形成,所以势必造成巨大的重复计算,这是个致命的伤。。。所以只好进行判重,所以只好又写了个双值哈希,确保一种选取情况对应一对唯一的哈希值,而对于一大堆乱七八糟的哈希值对,怎样判断是否存在呢?于是逗比的我又来个了平衡树进行查找,这样子算下来,时间复杂度 \(O\left({15}^{7}\times 7 Ans \log Ans \right)\)
1 /************************************************************** 2 Problem: 1675 3 User: HansBug 4 Language: Pascal 5 Result: Accepted 6 Time:2524 ms 7 Memory:2964 kb 8 ****************************************************************/ 9 10 const p=314159;q=951413; 11 type 12 pair=record 13 a0,b0:int64; 14 end; 15 var 16 i,j,k,l,m,n,head,tot,ans,av:longint; 17 lef,rig,fix:array[0..100000] of longint; 18 b:array[0..100000,1..2] of int64; 19 c,d:array[0..100,1..2] of longint; 20 a,e:array[0..10,0..10] of longint; 21 list:array[0..25,1..2] of int64; 22 ch:char; 23 procedure rt(var x:longint); 24 var l,f:longint; 25 begin 26 if (x=0) or (lef[x]=0) then exit; 27 f:=x;l:=lef[x]; 28 lef[f]:=rig[l]; 29 rig[l]:=f; 30 x:=l; 31 end; 32 procedure lt(var x:longint); 33 var r,f:longint; 34 begin 35 if (x=0) or (rig[x]=0) then exit; 36 f:=x;r:=rig[x]; 37 rig[f]:=lef[r]; 38 lef[r]:=f; 39 x:=r; 40 end; 41 function ins(var x:longint;y:longint):boolean; 42 begin 43 ins:=true; 44 if x=0 then 45 begin 46 x:=y; 47 exit; 48 end; 49 if (b[y,1]<b[x,1]) or ((b[y,1]=b[x,1]) and (b[y,2]<b[x,2])) then 50 begin 51 if lef[x]=0 then lef[x]:=y else ins:=ins(lef[x],y); 52 if fix[lef[x]]<fix[x] then rt(x); 53 end 54 else if (b[y,1]>b[x,1]) or ((b[y,1]=b[x,1]) and (b[y,2]>b[x,2])) then 55 begin 56 if rig[x]=0 then rig[x]:=y else ins:=ins(rig[x],y); 57 if fix[rig[x]]<fix[x] then lt(x); 58 end 59 else exit(false); 60 end; 61 function checkhash(t:pair):boolean; 62 begin 63 inc(tot); 64 b[tot,1]:=t.a0;b[tot,2]:=t.b0; 65 lef[tot]:=0;rig[tot]:=0;fix[tot]:=random(maxlongint); 66 checkhash:=ins(head,tot); 67 if not(checkhash) then dec(tot); 68 end; 69 function trans(x,y:longint):longint; 70 begin 71 trans:=(x-1)*5+y; 72 end; 73 function hashstate:pair; 74 var 75 i,j:longint;x,y:int64;t:pair; 76 begin 77 x:=0;y:=0; 78 for i:=1 to 7 do 79 begin 80 j:=trans(c[i,1],c[i,2]); 81 x:=(x+list[j,1]) mod q; 82 y:=(y+list[j,2]) mod p; 83 end; 84 t.a0:=x;t.b0:=y; 85 exit(t); 86 end; 87 procedure hashstartup; 88 var i:longint; 89 begin 90 list[0,1]:=1;list[0,2]:=1; 91 for i:=1 to 25 do 92 begin 93 list[i,1]:=(list[i-1,1]*p) mod q; 94 list[i,2]:=(list[i-1,2]*q) mod p; 95 end; 96 end; 97 procedure dfs(z:longint); 98 var i,j,k,l:longint; 99 begin 100 if z>7 then 101 begin 102 j:=0; 103 for i:=1 to 7 do inc(j,a[c[i,1],c[i,2]]); 104 if j<=3 then exit; 105 if checkhash(hashstate) then 106 begin 107 inc(ans); 108 end; 109 exit; 110 end; 111 l:=av; 112 for i:=1 to l do 113 begin 114 if e[d[i,1],d[i,2]]<>1 then continue; 115 c[z,1]:=d[i,1];c[z,2]:=d[i,2]; 116 e[d[i,1],d[i,2]]:=2; 117 if e[d[i,1]-1,d[i,2]]=0 then 118 begin 119 inc(av); 120 d[av,1]:=d[i,1]-1; 121 d[av,2]:=d[i,2]; 122 e[d[i,1]-1,d[i,2]]:=1; 123 end; 124 if e[d[i,1]+1,d[i,2]]=0 then 125 begin 126 inc(av); 127 d[av,1]:=d[i,1]+1; 128 d[av,2]:=d[i,2]; 129 e[d[i,1]+1,d[i,2]]:=1; 130 end; 131 if e[d[i,1],d[i,2]-1]=0 then 132 begin 133 inc(av); 134 d[av,1]:=d[i,1]; 135 d[av,2]:=d[i,2]-1; 136 e[d[i,1],d[i,2]-1]:=1; 137 end; 138 if e[d[i,1],d[i,2]+1]=0 then 139 begin 140 inc(av); 141 d[av,1]:=d[i,1]; 142 d[av,2]:=d[i,2]+1; 143 e[d[i,1],d[i,2]+1]:=1; 144 end; 145 dfs(z+1); 146 while av>l do 147 begin 148 e[d[av,1],d[av,2]]:=0; 149 d[av,1]:=0;d[av,2]:=0; 150 dec(av); 151 end; 152 e[d[i,1],d[i,2]]:=1; 153 end; 154 end; 155 begin 156 hashstartup; 157 tot:=0;head:=0;ans:=0;av:=0; 158 randomize; 159 fillchar(e,sizeof(e),0); 160 for i:=0 to 6 do 161 begin 162 e[i,0]:=1;e[0,i]:=1; 163 e[i,6]:=1;e[6,i]:=1; 164 end; 165 for i:=1 to 5 do 166 begin 167 for j:=1 to 5 do 168 begin 169 read(ch); 170 case upcase(ch) of 171 'H':a[i,j]:=0; 172 'J':a[i,j]:=1; 173 end; 174 end; 175 readln; 176 end; 177 for i:=1 to 5 do 178 for j:=1 to 5 do 179 begin 180 av:=0; 181 c[1,1]:=i;c[1,2]:=j; 182 if e[i-1,j]=0 then 183 begin 184 inc(av); 185 d[av,1]:=i-1;d[av,2]:=j; 186 e[i-1,j]:=1; 187 end; 188 if e[i+1,j]=0 then 189 begin 190 inc(av); 191 d[av,1]:=i+1;d[av,2]:=j; 192 e[i+1,j]:=1; 193 end; 194 if e[i,j-1]=0 then 195 begin 196 inc(av); 197 d[av,1]:=i;d[av,2]:=j-1; 198 e[i,j-1]:=1; 199 end; 200 if e[i,j+1]=0 then 201 begin 202 inc(av); 203 d[av,1]:=i;d[av,2]:=j+1; 204 e[i,j+1]:=1; 205 end; 206 e[i,j]:=2; 207 dfs(2); 208 while av>0 do 209 begin 210 e[d[av,1],d[av,2]]:=0; 211 d[av,1]:=0;d[av,2]:=0; 212 dec(av); 213 end; 214 e[i,j]:=0; 215 end; 216 writeln(ans); 217 readln; 218 end.
于是我很嗨皮的交了一下,结果是(上面的那个是这种新的算法,下面的是之前的纯暴力)
于是我再一次有了一种彻底被吓尿的赶脚QAQ,实在没想到这玩意常数会这么大,还有后来查了一下数据,事实证明在有些比较单调的图中,我程序的速度相当坑TT
所以只能优化啦——比如,我们不难发现每个块总有一个x值最小的点,于是可以在下面的搜索过程中限制扩张方向,只准向下、向右、向左(注意:不可以一一个点为基准,同时限制向下和向左,想想为什么^_^);还有,当当前的块里面已经出现4个H的时候,我觉得这个块就没任何继续下去的必要了对不——就算接下来全是J也没有用^_^;还有就是简单的常数优化了
于是再交了一次,结果如下(这两个都是优化过的,唯一的区别在于是否在过程和函数后面加了inline;)
于是,我终于战胜了原来的纯暴力,可实际上也不难发现一个问题——我后来写的优化程序有7KB还多,而简单的暴力只有2.5KB的样子,而且弄来弄去我最终的程序也才快了0.2s的样子,在考场上这根本不存在决定性作用。
显然,对这道题而言,还是朴素的暴力算法性价比高得多,尤其是考场上在极为有限的时间内,选择一个合适的方法尤其重要;不过我们还是不要为此导致不敢乱搞,脑洞还是要大开的^_^
优化代码:
1 /************************************************************** 2 Problem: 1675 3 User: HansBug 4 Language: Pascal 5 Result: Accepted 6 Time:1660 ms 7 Memory:2972 kb 8 ****************************************************************/ 9 10 const p=314159;q=951413; 11 type 12 pair=record 13 a0,b0:int64; 14 end; 15 var 16 i,j,k,l,m,n,head,tot,ans,av:longint; 17 lef,rig,fix:array[0..100000] of longint; 18 b:array[0..100000,1..2] of int64; 19 c,d:array[0..100,1..2] of longint; 20 a,e:array[0..10,0..10] of longint; 21 list:array[0..25,1..2] of int64; 22 ch:char; 23 procedure rt(var x:longint);inline; 24 var l,f:longint; 25 begin 26 if (x=0) or (lef[x]=0) then exit; 27 f:=x;l:=lef[x]; 28 lef[f]:=rig[l]; 29 rig[l]:=f; 30 x:=l; 31 end; 32 procedure lt(var x:longint);inline; 33 var r,f:longint; 34 begin 35 if (x=0) or (rig[x]=0) then exit; 36 f:=x;r:=rig[x]; 37 rig[f]:=lef[r]; 38 lef[r]:=f; 39 x:=r; 40 end; 41 function ins(var x:longint;y:longint):boolean;inline; 42 begin 43 ins:=true; 44 if x=0 then 45 begin 46 x:=y; 47 exit; 48 end; 49 if (b[y,1]<b[x,1]) or ((b[y,1]=b[x,1]) and (b[y,2]<b[x,2])) then 50 begin 51 if lef[x]=0 then lef[x]:=y else ins:=ins(lef[x],y); 52 if fix[lef[x]]<fix[x] then rt(x); 53 end 54 else if (b[y,1]>b[x,1]) or ((b[y,1]=b[x,1]) and (b[y,2]>b[x,2])) then 55 begin 56 if rig[x]=0 then rig[x]:=y else ins:=ins(rig[x],y); 57 if fix[rig[x]]<fix[x] then lt(x); 58 end 59 else exit(false); 60 end; 61 function checkhash(t:pair):boolean;inline; 62 begin 63 inc(tot); 64 b[tot,1]:=t.a0;b[tot,2]:=t.b0; 65 lef[tot]:=0;rig[tot]:=0;fix[tot]:=random(maxlongint); 66 checkhash:=ins(head,tot); 67 if not(checkhash) then dec(tot); 68 end; 69 function trans(x,y:longint):longint;inline; 70 begin 71 trans:=(x-1)*5+y; 72 end; 73 function hashstate:pair;inline; 74 var 75 i,j:longint;x,y:int64;t:pair; 76 begin 77 x:=0;y:=0; 78 for i:=1 to 7 do 79 begin 80 j:=trans(c[i,1],c[i,2]); 81 x:=(x+list[j,1]) mod q; 82 y:=(y+list[j,2]) mod p; 83 end; 84 t.a0:=x;t.b0:=y; 85 exit(t); 86 end; 87 procedure hashstartup;inline; 88 var i:longint; 89 begin 90 list[0,1]:=1;list[0,2]:=1; 91 for i:=1 to 25 do 92 begin 93 list[i,1]:=(list[i-1,1]*p) mod q; 94 list[i,2]:=(list[i-1,2]*q) mod p; 95 end; 96 end; 97 procedure dfs(z,t:longint);inline; 98 var i,j,k,l:longint; 99 begin 100 if (z-t)>4 then exit; 101 if z>7 then 102 begin 103 if checkhash(hashstate) then 104 begin 105 inc(ans); 106 end; 107 exit; 108 end; 109 l:=av; 110 for i:=1 to l do 111 begin 112 if e[d[i,1],d[i,2]]<>1 then continue; 113 c[z,1]:=d[i,1];c[z,2]:=d[i,2]; 114 e[d[i,1],d[i,2]]:=2; 115 if e[d[i,1]-1,d[i,2]]=0 then 116 begin 117 inc(av); 118 d[av,1]:=d[i,1]-1; 119 d[av,2]:=d[i,2]; 120 e[d[i,1]-1,d[i,2]]:=1; 121 end; 122 if e[d[i,1]+1,d[i,2]]=0 then 123 begin 124 inc(av); 125 d[av,1]:=d[i,1]+1; 126 d[av,2]:=d[i,2]; 127 e[d[i,1]+1,d[i,2]]:=1; 128 end; 129 if e[d[i,1],d[i,2]-1]=0 then 130 begin 131 inc(av); 132 d[av,1]:=d[i,1]; 133 d[av,2]:=d[i,2]-1; 134 e[d[i,1],d[i,2]-1]:=1; 135 end; 136 if e[d[i,1],d[i,2]+1]=0 then 137 begin 138 inc(av); 139 d[av,1]:=d[i,1]; 140 d[av,2]:=d[i,2]+1; 141 e[d[i,1],d[i,2]+1]:=1; 142 end; 143 dfs(z+1,t+a[d[i,1],d[i,2]]); 144 while av>l do 145 begin 146 e[d[av,1],d[av,2]]:=0; 147 d[av,1]:=0;d[av,2]:=0; 148 dec(av); 149 end; 150 e[d[i,1],d[i,2]]:=1; 151 end; 152 end; 153 begin 154 hashstartup; 155 tot:=0;head:=0;ans:=0;av:=0; 156 randomize; 157 fillchar(e,sizeof(e),0); 158 for i:=0 to 6 do 159 begin 160 e[i,0]:=1;e[0,i]:=1; 161 e[i,6]:=1;e[6,i]:=1; 162 end; 163 for i:=1 to 5 do 164 begin 165 for j:=1 to 5 do 166 begin 167 read(ch); 168 case upcase(ch) of 169 'H':a[i,j]:=0; 170 'J':a[i,j]:=1; 171 end; 172 end; 173 readln; 174 end; 175 for i:=1 to 5 do 176 begin 177 for j:=1 to 5 do c[i-1,j]:=1; 178 for j:=1 to 5 do 179 begin 180 av:=0; 181 c[1,1]:=i;c[1,2]:=j; 182 if e[i-1,j]=0 then 183 begin 184 inc(av); 185 d[av,1]:=i-1;d[av,2]:=j; 186 e[i-1,j]:=1; 187 end; 188 if e[i+1,j]=0 then 189 begin 190 inc(av); 191 d[av,1]:=i+1;d[av,2]:=j; 192 e[i+1,j]:=1; 193 end; 194 if e[i,j-1]=0 then 195 begin 196 inc(av); 197 d[av,1]:=i;d[av,2]:=j-1; 198 e[i,j-1]:=1; 199 end; 200 if e[i,j+1]=0 then 201 begin 202 inc(av); 203 d[av,1]:=i;d[av,2]:=j+1; 204 e[i,j+1]:=1; 205 end; 206 e[i,j]:=2; 207 dfs(2,a[i,j]); 208 while av>0 do 209 begin 210 e[d[av,1],d[av,2]]:=0; 211 d[av,1]:=0;d[av,2]:=0; 212 dec(av); 213 end; 214 e[i,j]:=0; 215 end; 216 end; 217 writeln(ans); 218 readln; 219 end.