您的位置:首页 > 其它

POJ3276 Face The Right Way——数学优化——pku3276

2011-09-21 15:24 495 查看
本题的朴素算法很容易想出:枚举k,然后判断这个k所需要的调转次数m,并用m更新答案。但是,在求k的掉转次数m时,只要找到一个面向后面的牛,就要将它后面的k头牛再调转一遍,这样很容易浪费大量时间。也就是说,在最坏的情况下,复杂度趋近于O(n^3)!这是不可以的,必须考虑优化。

优化方法如下:

在读入时做一个巧妙的处理,设map数组表示这个位置上牛的状况,map[i]=0表示这头牛的方向与前一头相同,map[i]=1表示这头牛的方向与前一头牛不同。默认第0头牛的方向为向前(也就是F)。我们要做的就是将所有的牛的方向调转至和第一头牛相同。

那么,每一次对于牛i,调转从牛i开始的k头牛,是不会改变这k头牛的位置关系的。改变只有牛i与牛i-1的关系以及牛i+k与牛i+k-1的关系。所以,只需要将map[i]改为1-map[i],将map[i+k]改为1-map[i+k]即可踩掉花哥无压力~

有图为证:



代码如下:

Program Cowturn;//By_Thispoet
Const
maxn=5001;
Var
i,m,n,temp,ans,ansnum				:Longint;
ch,c								:Char;
map,remap							:Array[1..maxn]of Longint;

Function Calc(i:Longint):Longint;
var j:Longint;
begin
for j:=1 to n do map[j]:=remap[j];
Calc:=0;m:=1;
while m<=n do
begin
while (map[m]=0)and(m<=n) do inc(m);
if (m>n-i+1)and(m<=n)then exit(maxlongint);
if m>n then exit;
inc(Calc);
map[i+m]:=1-map[i+m];
inc(m);
end;
end;

Procedure Printf();
begin
writeln(ansnum,' ',ans);
end;

BEGIN

readln(n);
c:='F';
for i:=1 to n do
begin
readln(ch);
if ch=c then remap[i]:=0 else
begin
c:=ch;
remap[i]:=1;
end;
end;

ans:=maxlongint;
for i:=1 to n do
begin
temp:=Calc(i);
if ans>temp then
begin
ans:=temp;
ansnum:=i;
end;
end;

printf();

END.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: