q就是我的数据了(jin)。现在,我要l这些数排序。假如我的电(sh)脑只能开?..99的数l,那计数排序算法最多对两位数进行排序。我把
每个八位C位两位地分成四段Q图1Q,分别q行四次计数排序。地球h都知道月份相同时应该看哪一日,因此我们看月份的大小时应该事先保证日已经有序。换
句话_(d)我们先对“最不重?#8221;的部分进行排序。我们先Ҏ(gu)有数的最后两位进行一ơ计数排序(?Q。注意观??6L(fng)MM??6L(fng)MMQ本ơ排
序中它们的属性值相同,׃计数排序是稳定的Q因?月䆾那个排完后依然在1月䆾那个的前头。接下来我们对百位和千位q行排序Q图3Q。你可以看到两个
26日的MM在这一ơ排序中分出?jin)大,而月份相同的MM依然保持日数有序Q因数排序是E_的)(j)。最后我们对q䆾排序Q图4Q,完成整个法。大安
是跨世纪的好儿童Q因此没有图5?jin)?br>
q?
U算法显然是正确的。它的复杂度一般写成O(d*(n+m))Q其中n表示n个数Qm是我开的数l大(本例中m=100Q,d是一个常数因子(本例?
d=4Q。我们认为它也是U性的?br>
问题五:(x)q样的排序方法还有什么致命的~陷Q?/strong>
STOP! You should think for a while.
?
使数据有30位,我们也可以用d=5?的Radix法q行排序。但Q要是给定的数据有无I多位怎么办?有h_(d)q可能么。这是可能的Q比如给定的数据
是小敎ͼ更准地_(d)实数Q。基于比较的排序可以区分355/113?#960;?
个大Q但你不知道Radix排序需要精到哪一位。这下惨?jin),实数的出现把貌似高科技的线性时间排序打回了(jin)农业时代。这Ӟ桶排序再度出山,挽救?jin)线性时
间排序?zhn)惨的命运?br>
问题六:(x)如何对实数进行线性时间排序?
STOP! You should think for a while.
?
们把问题化一下,l出的所有数都是0?之间的小数。如果不是,也可以把所有数同时除以一个大整数从而{化ؓ(f)q种形式。我们依然设立若q个Ӟ比如Q以
数点后面一位数Z据对所有数q行划分。我们仍然用链表把同一cȝC在一P不同的是Q每一个链表都是有序的。也是_(d)每一ơ读C个新的数都要q?
行一ơ插入排序。看我们的例子:(x)
A[]=
0.12345, 0.111, 0.618, 0.9, 0.99999
+---+---+---+---+---+---+---+---+---+---+
十分位:(x) | 0 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 |
+---+-o-+---+---+---+---+-o-+---+---+-o-+
| | |
A[2]=0.111 A[3]=0.618 A[4]=0.9
| |
A[1]=0.12345 A[5]=0.99999
假如再下一个读入的数是
0.122222Q这个数需要插入到十分位ؓ(f)1的那个链表里适当的位|。我们需要遍历该链表直到扑ֈW一个比0.122222大的敎ͼ在例子中则应该插?
到链表中A[2]和A[1]之间。最后,我们按顺序遍历所有链表,依次输出每个链表中的每个数?br> q个法昄是正的Q但复杂度显然不?
U性。事实上Q这U算法最坏情况下是O(n^2)的,因ؓ(f)当所有数的十分位都相同时法是一个插入排序。和原来一P我们下面要计算法的q_旉复杂
度,我们希望q种法的^均复杂度是线性的?br> q次^均复杂度我们用最W的办法。我们将出所有可能出现的情况的L间复杂度Q除以ȝ
情况敎ͼ得到q_的复杂度是多?br> 每个数都可能属于10个桶中的一个,n个数ȝ情况?0^nU。这个值是我们庞大的算式的分母部分?
如果一个桶里有K个元素,那么只与q个桶有关的操作有O(K^2)ơ,它就是一ơ插入排序的操作ơ数。下面计,?0^nU情况中QK0=1有多种?
c(din)K0=1表示Qn个数中只有一个数?hQ其余n-1个数的十分位只能在1?中选择。那么K0=1的情冉|C(n,1)*9^(n-1)Q而每
个K0=1的情况在0h中将产生1^2的复杂度。类似地QKi=p的情冉|为C(n,p)*9^(n-p)Q复杂度总计为C(n,p)*9^(n-
p)*p^2。枚举所有K的下标和p|累加hQ这个算式大家应该能写出来了(jin)Q但是这?#8230;…怎么啊。别怕,我们是搞计算机的Q拿出点和MO不一L(fng)?
西来。于是,Mathematica 5.0隆重dQ我做数学作业全靠它。它?yu)帮我们化简q个复杂的式子?br>
?
们遗憑֜发现Q虽然常数因子很(只有0.1Q,但算法的q_复杂度仍然是qx的。等一下,1/10的那?0是我们桶的个数吗Q那么我们ؓ(f)什么不把桶?
个数弄大点?我们q脆用m来表C桶的个敎ͼ重新计算一ơ:(x)
?
出来Q操作次Cؓ(f)O(n+n^2/m)。发C(jin)么,如果m=Θ(n)的话Q^均复杂度变成了(jin)O(n)。也是_(d)当桶的个数等于输入数据的个数Ӟ?
法是q_U性的?br> 我们在Hash表开散列的介l中重新提到q个l论?br>
且慢Q还有一个问题?0个桶以十分位?
数字归类Q那么n个桶用什么方法来分类呢?注意Q分cȝҎ(gu)需要满I一Q一个数分到每个桉的概率相同(q样才有我们上面的结论)(j)Q二Q所有桶里容U_
素的范围必须是连l的。根据这两个条gQ我们有办法把所有数恰好分ؓ(f)ncR我们的输入数据不是都在0?之间么?只需要看q些C以n的整数部分是多少?
行了(jin)Q读C个数后乘以n取整得几插入到几号桉。这本质上相当于把区间[0,1)q_分成n份?br>
问题七:(x)?
没有复杂度低于线性的排序法
STOP! You should
think for a while.
我们从O(n^2)走向O(nlogn)Q又从O(nlogn)走向U性,
每一ơ我们都讨论?jin)复杂度下限的问题,?gu)讨论的结果提Z(jin)更优的算法。这ơȝ不行?jin),不可能有比线性还快的法?jin),因?f)——你d、输出数据至就需
要线性的旉。排序算法之旅在U性时间复杂度q一站终止了(jin)Q所有十U排序算法到q里介绍完毕?jin)?br>
文章有越写越?
的趋势了(jin)Q我(g)查v来也来篏?jin)。我又看?jin)三遍,应该没问题?jin)。群众的眼睛是雪亮的Q恳请大家帮我找错?br>
x
<- x # y
y <- x @ y
x <- x @ y
procedure
swap(var a,b:longint);
begin
a:=a + b;
b:=a - b;
a:=a - b;
end;
procedure swap(var a,b:longint);
begin
a:=a
xor b;
b:=a xor b;
a:=a xor b;
end;
var
a:word;
begin
a:=100;
a:=not a;
writeln(a);
end.
#include
<stdio.h>
int main()
{
unsigned short a=100;
a
= ~a;
printf( "%d\n", a );
return 0;
}
var
a,b:integer;
begin
a:=$0000;
b:=$0001;
write(a,' ',b,' ');
a:=$FFFE;
b:=$FFFF;
write(a,' ',b,' ');
a:=$7FFF;
b:=$8000;
writeln(a,'
',b);
end.
#include <stdio.h>
int main()
{
short
int a, b;
a = 0×0000;
b = 0×0001;
printf( "%d %d
", a, b );
a = 0xFFFE;
b = 0xFFFF;
printf( "%d %d
", a, b );
a = 0×7FFF;
b = 0×8000;
printf( "%d
%d\n", a, b );
return 0;
}
===== 真正强的东西来了(jin)Q?nbsp; =====
二进制中?有奇Cq是偶数?br> 我们可以用下面的代码来计?
一?2位整数的二进制中1的个数的奇偶性,当输入数据的二进制表C里有偶C数字1时程序输?Q有奇数个则输出1。例如,1314520的二q制
101000000111011011000中有9?Q则x=1314520时程序输??br>var
i,x,c:longint;
begin
readln(x);
c:=0;
for i:=1 to
32 do
begin
c:=c + x and 1;
x:=x shr 1;
end;
writeln( c and 1 );
end.
但这L(fng)效率q不高,位运的奇之处q?
没有体现出来?br> 同样是判断二q制?的个数的奇偶性,下面q段代码强?jin)。你能看?gu)个代码的原理吗?br>var
x:longint;
begin
readln(x);
x:=x xor (x shr 1);
x:=x xor (x shr 2);
x:=x xor (x shr 4);
x:=x xor (x shr 8);
x:=x xor (x shr 16);
writeln(x and 1);
end.
Z(jin)说明
上面q段代码的原理,我们q是?314520出来说事?314520的二q制?01000000111011011000Q第一ơ异或操作的l果?
下:(x)
00000000000101000000111011011000
XOR 0000000000010100000011101101100
---------------------------------------
00000000000111100000100110110100
?
到的l果是一个新的二q制敎ͼ其中双vWi位上的数表示原数中第i和i+1位上有奇C1q是偶数?。比如,最双那个0表示原数末两位有偶数?Q右
L(fng)3位上?pC原数的q个位置和前一个位|中有奇C1。对q个数进行第二次异或的结果如下:(x)
00000000000111100000100110110100
XOR
000000000001111000001001101101
---------------------------------------
00000000000110011000101111011001
l?
果里的每?表示原数的该位置?qing)其前面三个位置中共有奇C1Q每?pC原数对应的四个位置上共偶数?。一直做到第五次异或l束后,得到的二q制?
的最末位pC整?2位数里有多少?Q这是我们最l想要的{案?br>
计算二进制中?的个?br> 同样假设x是一?
32位整数。经q下面五ơ赋值后Qx的值就是原数的二进制表CZ数字1的个数。比如,初始时x?314520Q网友抓狂:(x)能不能换一个数啊)(j)Q那么最?
x变成了(jin)9Q它表示1314520的二q制中有9??br>x := (x and $55555555) + ((x shr 1)
and $55555555);
x := (x and $33333333) + ((x shr 2) and $33333333);
x := (x and $0F0F0F0F) + ((x shr 4) and $0F0F0F0F);
x := (x and
$00FF00FF) + ((x shr 8) and $00FF00FF);
x := (x and $0000FFFF) +
((x shr 16) and $0000FFFF);
Z(jin)便于解说Q我们下面仅说明q个E序是如何对一?位整数进
行处理的。我们拿数字211Q我们班某MM的生日)(j)来开刀?11的二q制?1010011?br>
+---+---+---+---+---+---+---+---+
|
1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | <---原数
+---+---+---+---+---+---+---+---+
| 1
0 | 0 1 | 0 0 | 1 0 | <---W一ơ运后
+-------+-------+-------+-------+
| 0
0 1 1 | 0 0 1 0 | <---W二ơ运后
+---------------+---------------+
| 0
0 0 0 0 1 0 1 | <---W三ơ运后Q得Cؓ(f)5
+-------------------------------+
?
个程序是一个分ȝ思想。第一ơ我们把每相?c)两位加v来,得到每两位里1的个敎ͼ比如前两?0pC原数的前两位有2?。第二次我们l箋两两?
加,10+01=11Q?0+10=10Q得到的l果?0110010Q它表示原数?位有3?Q末4位有2?。最后一ơ我们把0011?010
加v来,得到的就是整个二q制?的个数。程序中巧妙C用取位和右移Q比如第二行?33333333的二q制?0110011001100….Q用
它和x做andq算q当于?为单位间隔取数。shr的作用就是让加法q算的相同数位对齐?br>
二分查找32位整数的前导0个数
q?
里用的C语言Q我直接Copy的Hacker's
Delight上的代码。这D代码写成C要好看些Q写成Pascal的话?x)出现很多begin和endQ搞得代码很隄。程序思想是二分查找,应该很简
单,我就不细说了(jin)?br>int nlz(unsigned x)
{
int n;
if (x
== 0) return(32);
n = 1;
if ((x >> 16) == 0) {n = n
+16; x = x <<16;}
if ((x >> 24) == 0) {n = n + 8; x = x
<< 8;}
if ((x >> 28) == 0) {n = n + 4; x = x <<
4;}
if ((x >> 30) == 0) {n = n + 2; x = x << 2;}
n = n - (x >> 31);
return n;
}
只用位运来?
l对?br> q是一个非常有的问题。大家先自己x吧,Ctrl+A昄{案?br> {案Q假设x?2位整敎ͼ则x xor
(not (x shr 31) + 1) + x shr 31的结果是x的绝对?br> x shr
31是二q制的最高位Q它用来表示x的符受如果它?Qx为正Q,则not (x shr 31) +
1{于$00000000Q异或Q何数l果都不变;如果最高位?QxQ,则not (x shr 31) +
1{于$FFFFFFFFQx异或它相当于所有数位取反,异或完后再加一?br>
高低位交?br> q个?/a>实际上是我出的,做ؓ(f)学校内部NOIp模拟赛的W一题。题目是q样Q?br>
l出一个小?^32的正整数。这个数可以用一?2位的二进制数表示Q不?2位用0补Q。我们称q个二进 制数的前16位ؓ(f)“高位”Q后16位ؓ(f)“低位”。将它的高低位交换,我们可以得到一个新的数。试问这个新的数是多(用十q制表示Q?br> 例如Q? ?314520用二q制表示?000 0000 0001 0100 0000 1110 1101 1000Q添加了(jin)11个前?补?2位)(j)Q其中前16位ؓ(f)高位Q即0000 0000 0001 0100Q后16位ؓ(f)低位Q即0000 1110 1101 1000。将它的高低位进行交换,我们得到?jin)一个新的二q制?000 1110 1101 1000 0000 0000 0001 0100。它x十进制的249036820?
当时几乎没有人想到用一句位操作来代替冗长的E序。用位q算的话两句话就完了(jin)?br>var
n:dword;
begin
readln( n );
writeln( (n shr 16) or
(n shl 16) );
end.
而事实上QPascal有一个系l函数swap直接可以用?br>
?
q制逆序
下面的程序读入一?2位整数ƈ输出它的二进制倒序后所表示的数?br> 输入Q?
1314520 Q二q制?0000000000101000000111011011000Q?br> 输出Q?
460335104 Q二q制?0011011011100000010100000000000Q?br>var
x:dword;
begin
readln(x);
x := (x and $55555555) shl 1
or (x and $AAAAAAAA) shr 1;
x := (x and $33333333) shl 2 or (x
and $CCCCCCCC) shr 2;
x := (x and $0F0F0F0F) shl 4 or (x and
$F0F0F0F0) shr 4;
x := (x and $00FF00FF) shl 8 or (x and
$FF00FF00) shr 8;
x := (x and $0000FFFF) shl 16 or (x and
$FFFF0000) shr 16;
writeln(x);
end.
它的原理和刚才求二进制中1
的个数那个例题是大致相同的。程序首先交换每盔R两位上的敎ͼ以后把互怺换过的数看成一个整体,l箋q行?位ؓ(f)单位、以4位ؓ(f)单位的左叛_换操作。我
们再ơ用8位整?11来演C程序执行过E:(x)
+---+---+---+---+---+---+---+---+
| 1 | 1 | 0
| 1 | 0 | 0 | 1 | 1 | <---原数
+---+---+---+---+---+---+---+---+
| 1
1 | 1 0 | 0 0 | 1 1 | <---W一ơ运后
+-------+-------+-------+-------+
| 1
0 1 1 | 1 1 0 0 | <---W二ơ运后
+---------------+---------------+
| 1
1 0 0 1 0 1 1 | <---W三ơ运后
+-------------------------------+
Copyright
也很?br>writeln('Matrix' , 42 XOR 105 , '原创Q{贴请注明出处');
今天我们来看两个E微复杂一点的例子?br>
n皇后问题位运版
n皇后问题是啥我就不说?jin)吧Q学~程的肯定都见过。下?
的十多行代码是n皇后问题的一个高效位q算E序Q看到过的h都夸它牛。初始时Qupperlim:=(1 shl
n)-1。主E序调用test(0,0,0)后sum的值就是n皇后ȝ解数。拿q个MUSACOQ?.3sQ暴爽?br>procedure
test(row,ld,rd:longint);
var
pos,p:longint;
begin
{
1} if row<>upperlim then
{ 2} begin
{ 3}
pos:=upperlim and not (row or ld or rd);
{ 4} while pos<>0
do
{ 5} begin
{ 6} p:=pos and -pos;
{
7} pos:=pos-p;
{ 8} test(row+p,(ld+p)shl 1,(rd+p)shr
1);
{ 9} end;
{10} end
{11} else inc(sum);
end;
?
一看似乎完全摸不着头脑Q实际上整个E序是非常容易理解的。这里还是徏议大家自己单步运行一探究竟,实在没研I出来再看下面的解说?br>
?
普通算法一Pq是一个递归q程Q程序一行一行地L可以攄后的地方。过E带三个参数Qrow、ld和rdQ分别表C在U列和两个对角线方向的限制条?
下这一行的哪些地方不能放。我们以6×6的棋盘ؓ(f)例,看看E序是怎么工作的。假讄在已l递归到第四层Q前三层攄子已l标在左图上?jin)。红艌Ӏ蓝色和l色
的线分别表示三个方向上有冲突的位|,位于该行上的冲突位置qrow、ld和rd中的1来表C。把它们三个qv来,得到该行所有的位Q取反后得到所
有可以放的位|(用pos来表C)(j)。前面说q?a相当于not a + 1Q这里的代码W?行就相当于pos and (not pos +
1)Q其l果是取出最双的那?。这PppC行的某个可以攑֭的位|,把它从pos中移除ƈ递归调用testq程。注意递归调用时三个参数的?
化,每个参数都加上了(jin)一个禁位,但两个对角线方向的禁位对下一行的影响需要^UM位。最后,如果递归到某个时候发现row=111111?jin),说明六个皇?
全放q去?jin),此时E序从第1行蟩到第11行,扑ֈ的解的个数加一?br>
~~~~====~~~~===== 华丽的分割线
=====~~~~====~~~~
Gray?br> 假如我有4个潜在的GFQ我需要决定最l到底和谁在一赗一个简单的办法
是Q依ơ和每个MM交往一D|_(d)最后选择l我带来?#8220;满意?#8221;最大的MM。但看了(jin)dd牛的理论后,
事情开始变得复杂了(jin)Q我可以选择和多个MM在一赗这P需要考核的状态变成了(jin)2^4=16U(当然包括0000q一状态,因ؓ(f)我有可能是玻璃)(j)。现在的
问题是Q我应该用什么顺序来遍历q?6U状态呢Q?br> 传统的做法是Q用二进制数的顺序来遍历所有可能的l合。也是_(d)我需要以
0000->0001->0010->0011->0100->…->1111q样的顺序对每种状态进行测试。这?
序很不U学Q很多时候状态的转移都很耗时。比如从0111?000时我需要暂时甩掉当前所有的3个MMQ然后去把第4个MM。同时改变所有MM与我?
关系是一件何{巨大的工程啊。因此,我希望知道,是否有一U方法可以得,从没有MMq一状态出发,每次只改变我和一个MM的关p(q或者甩Q,15ơ操
作后恰好遍历完所有可能的l合Q最l状态不一定是1111Q。大家自己先试一试看行不行?br> 解决q个问题的方法很巧妙。我们来说明Q假如我
们已l知道了(jin)n=2时的合法遍历序Q我们如何得到n=3的遍历顺序。显?dng)n=2的遍历顺序如下:(x)
00
01
11
10
?
可能已经惛_?jin)如何把上面的遍历顺序扩展到n=3的情c(din)n=3时一共有8U状态,其中前面4个把n=2的遍历顺序照搬下来,然后把它们对U翻折下dƈ?
最前面加上1作ؓ(f)后面4个状态:(x)
000
001
011
010 ↑
--------
110 ↓
111
101
100
?
q种Ҏ(gu)得到的遍历顺序显然符合要求。首先,上面8个状态恰好是n=3时的所?U组合,因ؓ(f)它们是在n=2的全部四U组合的基础上考虑选不选第3个元?
所得到的。然后我们看刎ͼ后面一半的状态应该和前面一半一h?#8220;盔R状态间仅一位不?#8221;的限Ӟ?#8220;镜面”处则是最前面那一位数不同。再ơ翻折三阉?
序Q我们就得到?jin)刚才的问题的答案?x)
0000
0001
0011
0010
0110
0111
0101
0100
1100
1101
1111
1110
1010
1011
1001
1000
q?
U遍历顺序作ZU编码方式存在,叫做Gray码(写个中文让蜘蛛来抓:(x)格雷码)(j)。它的应用范围很qѝ比如,n阶的Gray码相当于在nl立方体上的
Hamilton回\Q因为沿着立方体上的边C步,nl坐标中只会(x)有一个值改变。再比如QGray码和Hanoi塔问题等仗Gray码改变的是第几个
敎ͼHanoi塔就该移动哪个盘子。比如,3阶的Gray码每ơ改变的元素所在位|依ơؓ(f)1-2-1-3-1-2-1Q这正好?阶Hanoi塔每ơ移?
盘子~号。如果我们可以快速求出Gray码的Wn个数是多,我们可以输ZQ意步数后Hanoi塔的Ud步骤。现在我告诉你,Gray码的Wn个数Q从
0vQ是n xor (n shr 1)Q你能想出来q是Z么吗Q先自己x吧?br>
下面我们把二q制数和Gray码都写在?
面,可以看到左边的数异或自n右移的结果就{于双的数?br>
二进制数 Gray?br> 000 000
001 001
010 011
011 010
100
110
101 111
110 101
111 100
?
二进制数的角度看Q?#8220;镜像”位置上的数即是对原数q行notq算后的l果。比如,W?个数010和倒数W?个数101的每一位都正好相反。假设这两个数分
别ؓ(f)x和yQ那么x xor (x shr 1)和y xor (y shr
1)的结果只有一点不同:(x)后者的首位?Q前者的首位?。而这正好是Gray码的生成Ҏ(gu)。这p明了(jin)QGray码的Wn个数实是n xor (n
shr 1)?br>
今年四月?a target="_blank">mashuol?
我看?a target="_blank">q道?/a>Q是二维意义上的Gray码。题目大意是_(d)??^(n+m)-1的数写成2^n *
2^m的矩阵,使得位置盔R两数的二q制表示只有一位之差。答案其实很单,所有数都是由m位的Gray码和n位Gray码拼接而成Q需要用左移操作?
orq算完成。完整的代码如下Q?br>var
x,y,m,n,u:longint;
begin
readln(m,n);
for x:=0 to 1 shl m-1 do begin
u:=(x xor (x
shr 1)) shl n; //输出数的左边是一个m位的Gray?br> for y:=0 to 1 shl n-1 do
write(u or (y xor (y shr 1)),' '); //q上一个n位Gray?br> writeln;
end;
end.
Matrix67原创
转脓(chung)h明出?/p>
位运简介及(qing)实用技巧(四)(j)Q实战篇
下面
分n的是我自己写的三个代码,里面有些题目也是我自己出的。这些代码都是在我的Pascal时代写的Q恕不提供C语言?jin)。代码写得ƈ不好Q我只是惛_诉大
家位q算在实战中的应用,包括?jin)搜索和状态压~DP斚w的题目。其实大家可以在|上扑ֈ更多用位q算优化的题目,q里整理Z些自己写的代码,只是Z(jin)?
创系列文章的完整性。这一pd文章到这里就l束?jin),希望大家能有所收获?br> Matrix67原创Q{贴请注明出处?br>
Problem : 费解的开?br>
题目来源
06 qNOIp模拟赛(一Q?by Matrix67 W四?br>
问题描述
你玩q?#8220;拉灯”游戏吗?25盏灯排成一?×5的方 形。每一个灯都有一个开养I游戏者可以改变它的状态。每一步,游戏者可以改变某一个灯的状态。游戏者改变一个灯的状态会(x)产生q锁反应Q和q个灯上下左右相 ?c)灯也要相应地改变其状态?br> 我们用数?#8220;1”表示一盏开着的灯Q用数字“0”表示关着的灯。下面这U状?br>
10111
01101
10111
10000
11011
? 改变?jin)最左上角的灯的状态后变成:(x)
01111
11101
10111
10000
11011
? 改变它正中间的灯后状态将变成Q?br>
01111
11001
11001
10100
11011
l? 定一些游戏的初始状态,~写E序判断游戏者是否可能在6步以内所有的灯都变亮?br>
输入格式
W一行有一个正整数nQ代表数 据中共有n个待解决的游戏初始状态?br> 以下若干行数据分为nl,每组数据?行,每行5个字W。每l数据描qC(jin)一个游戏的初始状态。各l数 据间用一个空行分隔?br> 对于30%的数据,n<=5Q?br> 对于100%的数据,n<=500?br>
? 出格?br> 输出数据一共有n行,每行有一个小于等?的整敎ͼ它表C对于输入数据中对应的游戏状态最需要几步才能所有灯变亮?br> ? 于某一个游戏初始状态,?步以内无法所有灯变亮Q请输出“-1”?br>
样例输入
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
? 例输?br>3
2
-1
E序代码const
BigPrime=3214567;
MaxStep=6;
type
pointer=^rec;
rec=record
v:longint;
step:integer;
next:pointer;
end;
var
total:longint;
hash:array[0..BigPrime-1]of pointer;
q:array[1..400000]of rec;
function
update(a:longint;p:integer):longint;
begin
a:=a xor (1 shl p);
if p mod 5<>0 then a:=a xor (1 shl (p-1));
if (p+1) mod
5<>0 then a:=a xor (1 shl (p+1));
if p<20 then a:=a xor
(1 shl (p+5));
if p>4 then a:=a xor (1 shl (p-5));
exit(a);
end;
function find(a:longint;step:integer):boolean;
var
now:pointer;
begin
now:=hash[a mod BigPrime];
while
now<>nil do
begin
if now^.v=a then exit(true);
now:=now^.next;
end;
new(now);
now^.v:=a;
now^.step:=step;
now^.next:=hash[a mod BigPrime];
hash[a mod BigPrime]:=now;
total:=total+1;
exit(false);
end;
procedure solve;
var
p:integer;
close:longint=0;
open:longint=1;
begin
find(1 shl 25-1,0);
q[1].v:=1 shl 25-1;
q[1].step:=0;
repeat
inc(close);
for p:=0 to 24 do
if
not find(update(q[close].v,p),q[close].step+1) and
(q[close].step+1<MaxStep) then
begin
open:=open+1;
q[open].v:=update(q[close].v,p);
q[open].step:=q[close].step+1;
end;
until close>=open;
end;
procedure
print(a:longint);
var
now:pointer;
begin
now:=hash[a
mod BigPrime];
while now<>nil do
begin
if
now^.v=a then
begin
writeln(now^.step);
exit;
end;
now:=now^.next;
end;
writeln(-1);
end;
procedure main;
var
ch:char;
i,j,n:integer;
t:longint;
begin
readln(n);
for i:=1
to n do
begin
t:=0;
for j:=1 to 25 do
begin
read(ch);
t:=t*2+ord(ch)-48;
if j mod 5=0 then
readln;
end;
print(t);
if i<n then readln;
end;
end;
begin
solve;
main;
end.
======================= ?
感的分割U?nbsp; =======================
Problem : garden / 和MM逛花?br>
题目来源
07qMatrix67生日邀(g)误 W? 四题
问题描述
花园设计Q简单就是美。Matrix67常去的花园有着非常单的布局Q花园的所有景点的位置都是“? ?#8221;?jin)的Q这些景点可以看作是q面坐标上的格点。相?c)景点之间有小路相q,q些\全部q于坐标u。景点和\l成?jin)一?#8220;不完整的|格”?br> 一 个典型的花园布局如左图所C。花园布局??列的|格上,花园?6个景点的位置用红色标注在?jin)图中。黑色线条表C景炚w的小路,其余灰色部分实际q不 存在?br>
Matrix67 的生日那天,他要带着他的MM在花园里游玩。Matrix67不会(x)带MM两次l过同一个景点,因此每个景点最多被游览一ơ。他和他的MM边走边聊Q他们是 如此的投入以致于他们从不?#8220;d地拐?#8221;。也是_(d)除非前方已没有景Ҏ(gu)是前方的景点已经讉Kq,否则他们?x)一直往前走下去。当前方景点不存在或已游 览过ӞMatrix67?x)带MM另选一个方向l前q。由于景点个数有限,讉Kq的景点越来越多,q早?x)出C能再走的情况Q即四个方向上的盔R景点 都访问过?jin)?j)Q此时他们将l束花园的游览。Matrix67希望知道以这U方式游览花园是否有可能遍历所有的景点。Matrix67可以选择从Q意一个景 点开始游览,以Q意一个景点结束?br> 在上图所C的花园布局中,一U可能的游览方式如右图所C。这U浏览方式从(1,2)出发Q以(2,4) l束Q经q每个景Ҏ(gu)好一ơ?br>
输入格式
W一行输入两个用I格隔开的正整数m和nQ表C园被布局在m行n列的|格上?br> ? 下m行每行n个字W,字符“0”表示该位|没有景点,字符“1”表示对应位置有景炏V这些数字之间没有空根{?br>
输出格式
? 的程序需要寻找满?#8220;不主动拐?#8221;性质且遍历所有景点的游览路线?br> 如果没有q样的游览\U,误Z?#8220;Impossible”Q不带引 P注意大小写)(j)?br> 如果存在游览路线Q请依次输出你的Ҏ(gu)中访问的景点的坐标,每行输出一个。坐标的表示格式?#8220;(x,y)”Q代表第x 行第y列?br> 如果有多U方案,你只需要输出其中一U即可。评系l可以判断你的方案的正确性?br>
样例输入
6 4
1100
1001
1111
1100
1110
1110
? 例输?br>(1,2)
(1,1)
(2,1)
(3,1)
(4,1)
(5,1)
(6,1)
(6,2)
(6,3)
(5,3)
(5,2)
(4,2)
(3,2)
(3,3)
(3,4)
(2,4)
? 据规?br> 对于30%的数据,n,m<=5Q?br> 对于100%的数据,n,m<=10?
E序代码Q?br>program garden;
const
dir:array[1..4,1..2]of integer=
((1,0),(0,1),(-1,0),(0,-1));
type
arr=array[1..10]of integer;
rec=record x,y:integer;end;
var
map:array[0..11,0..11]of boolean;
ans:array[1..100]of rec;
n,m,max:integer;
step:integer=1;
state:arr;
procedure
readp;
var
i,j:integer;
ch:char;
begin
readln(m,n);
for i:=1 to n do
begin
for j:=1 to m
do
begin
read(ch);
map[i,j]:=(ch='1');
inc(max,ord( map[i,j] ))
end;
readln;
end;
end;
procedure
writep;
var
i:integer;
begin
for i:=1 to step do
writeln(
'(' , ans[i].x , ',' , ans[i].y , ')' );
end;
procedure
solve(x,y:integer);
var
tx,ty,d:integer;
step_cache:integer;
state_cache:arr;
begin
step_cache:=step;
state_cache:=state;
if step=max then
begin
writep;
exit;
end;
for d:=1 to 4
do
begin
tx:=x+dir[d,1];
ty:=y+dir[d,2];
while
map[tx,ty] and ( not state[tx] and(1 shl (ty-1) )>0) do
begin
inc(step);
ans[step].x:=tx;
ans[step].y:=ty;
state[tx]:=state[tx] or ( 1 shl (ty-1) );
tx:=tx+dir[d,1];
ty:=ty+dir[d,2];
end;
tx:=tx-dir[d,1];
ty:=ty-dir[d,2];
if
(tx<>x) or (ty<>y) then solve(tx,ty);
state:=state_cache;
step:=step_cache;
end;
end;
{====main====}
var
i,j:integer;
begin
assign(input,'garden.in');
reset(input);
assign(output,'garden.out');
rewrite(output);
readp;
for i:=1 to n do
for j:=1 to m do
if map[i,j] then
begin
ans[1].x:=i;
ans[1].y:=j;
state[i]:=1
shl (j-1);
solve(i,j);
state[i]:=0;
end;
close(input);
close(output);
end.
======================= ?
感的分割U?nbsp; =======================
Problem : cowfood / 玉米?br>
题目来源
USACO月赛
? 题描q?br> 农夫U翰购买?jin)一处肥沃的矩Ş牧场Q分成M*N(1<=M<=12; 1<=N<=12)个格子。他惛_那里的一些格子中U植味的玉c뀂遗憄是,有些格子区域的土地是贫瘠的,不能耕种?br> _明 的约知道奶牛们q食时不喜欢和别的牛盔RQ所以一旦在一个格子中U植玉米Q那么他׃?x)在盔R的格子中U植Q即没有两个被选中的格子拥有公p。他q没 有最l确定哪些格子要选择U植玉米?br> 作ؓ(f)一个思想开明的人,农夫U翰希望考虑所有可行的选择格子U植Ҏ(gu)。由于太开明,他还考虑一个格? 都不选择的种植方案!请帮助农夫约确定种植方案L?br>
输入格式:
W一行:(x)两个用空格分隔的整数M和N
W? 二行到第M+1行:(x)Wi+1行描q牧场第i行每个格子的情况QN个用I格分隔的整敎ͼ表示q个格子是否可以U植Q?表示肥沃的、适合U植Q?表示贫瘠的? 不可U植Q?br>
输出格式
一个整敎ͼ农夫U翰可选择的方案L除以 100,000,000 的余?br>
样例输入
2 3
1 1 1
0 1 0
样例输出
9
样例说明
l可以种植玉c的格子~? P(x)
1 2 3
4
? U一个格子的Ҏ(gu)有四U?1,2,3?)Q种植两个格子的Ҏ(gu)有三U?13,14?4)Q种植三个格子的Ҏ(gu)有一U?134)Q还有一U什么格子都? U?br> 4+3+1+1=9?br>
数据规模
对于30%的数据,N,M<=4Q?br> 对于 100%的数据,N,M<=12?
E序代码Q?br>program cowfood;
const
d=100000000;
MaxN=12;
var
f:array[0..MaxN,1..2000]of
longint;
w:array[1..2000,1..2000]of boolean;
st:array[0..2000]of integer;
map:array[0..MaxN]of integer;
m,n:integer;
function Impossible(a:integer):boolean;
var
i:integer;
flag:boolean=false;
begin
for i:=1 to MaxN do
begin
if flag and (a and 1=1) then exit(true);
flag:=(a
and 1=1);
a:=a shr 1;
end;
exit(false);
end;
function
Conflict(a,b:integer):boolean;
var
i:integer;
begin
for i:=1 to MaxN do
begin
if (a and 1=1) and (b and 1=1)
then exit(true);
a:=a shr 1;
b:=b shr 1;
end;
exit(false);
end;
function CanPlace(a,b:integer):boolean;
begin
exit(a or b=b);
end;
procedure FindSt;
var
i:integer;
begin
for i:=0 to 1 shl MaxN-1 do
if not
Impossible(i) then
begin
inc(st[0]);
st[st[0]]:=i;
end;
end;
procedure Init;
var
i,j:integer;
begin
for i:=1 to st[0] do
for j:=i to
st[0] do
if not Conflict(st[i],st[j]) then
begin
w[i,j]:=true;
w[j,i]:=true;
end;
end;
procedure
Readp;
var
i,j,t,v:integer;
begin
readln(m,n);
for i:=1 to m do
begin
v:=0;
for j:=1 to n do
begin
read(t);
v:=v*2+t;
end;
map[i]:=v;
readln;
end;
end;
procedure Solve;
var
i,j,k:integer;
begin
f[0,1]:=1;
map[0]:=1 shl n-1;
for i:=1 to m do
for
j:=1 to st[0] do
if not CanPlace(st[j],map[i]) then f[i,j]:=-1
else
for k:=1 to st[0] do if (f[i-1,k]<>-1) and w[j,k]
then
f[i,j]:=(f[i,j]+f[i-1,k]) mod d;
end;
procedure
Writep;
var
j:integer;
ans:longint=0;
begin
for
j:=1 to st[0] do
if f[m,j]<>-1 then ans:=(ans+f[m,j])
mod d;
writeln(ans);
end;
begin
assign(input,'cowfood.in');
reset(input);
assign(output,'cowfood.out');
rewrite(output);
FindSt;
Init;
Readp;
Solve;
Writep;
close(input);
close(output);
end.