您的位置:首页 > 其它

解题报告 比赛

2011-08-08 14:12 225 查看
[/b]

1. [/b]题目[/b]

比赛([/b]Pk.pas/c/cpp[/b])[/b][/b]

题目描述[/b][/b]

新兵们一般在部队没什么娱乐活动,而且还老有个警官在旁边即即歪歪,所以他们总要找个法子发一下怒气,所以有时候两个不同营的新兵就喜欢一起打架。。。。。。[/b] A[/b]营和[/b]B[/b]营就是典型的例子。而且他们破坏力很大,常常把操场打得这里坑一块那里坑一块,警官很头疼,因为都要他掏腰包。。。。。。[/b][/b]

[/b]为了减少损失,他决定每隔一段时间由他自己组织搞次比赛(打架)。[/b][/b]

[/b]比赛开始时两个营新兵排成两个队,每个士兵有一个破坏值,然后由警官来安排比赛的人,分任意次来[/b]PK[/b],可以是单挑,群挑,或者是单挑群(呵呵,警官只在乎修整费用最少)具体规则如下:[/b][/b]

从后往前,每次从A营选出连续k1(k1>0)个人,从B营选出连续k2(k2>0)个人进行pk。那么这次破坏导致操场的修整费用为 (S1-K1)*(S2-K2)。比赛直到两个队伍都为空时结束。而这次比赛的总修整费用就为每次PK修整费用的和。[/b]

警官拜托你的是使这次比赛的费用最小。[/b]

[/b]

输入数据[/b][/b]

[/b]第一行两个正整数L1,L2分别表示两营的人数;[/b]

第二行L1个正整数,描述A 营每个人的破坏值[/b]

第三行L2个正整数,描述B 营每个人的破坏值[/b]

1<=L1,L2<=2000[/b]

输出数据[/b][/b]

一个正整数表示操场的最小修整费用[/b]

[/b]

[/b]

样例输入[/b][/b]

3 2[/b]

1 2 3[/b]

1 2[/b]

样例输出[/b][/b]

2[/b]

[/b]

2. [/b]题目实质[/b]

动规求最优解。(废话)[/b]

3. [/b]算法[/b]

地球人都能看出来是动规,问题是,方程怎么写?[/b]

第一种:[/b]

f[i,j] [/b]代表消去序列A1[/b]的i->l1[/b],序列A2[/b]的j->l2[/b],[/b]

设A1[i]+A1[i+1]+[/b]……+A1[l1]=Si;A2[j]+A2[j+1]+[/b]……+A2[l2]=Tj ;[/b]则状态转移方程为: f[i,j]:=min{ f[p,q]+(Si-Sp-p+i)*(Tj-Tq-q+j) | (i<p<=l1+1,j<q<=l2+1) }[/b]

初始条件为 f[l1+1,l2+1]=0 ;[/b]

但这样是 O(L^4) [/b]。[/b]

观察(S1-K1)*(S2-K2)[/b]的(S1-K1)[/b]可以写成[(A1[1]-1)+(A1[2]-1)+[/b]……+(A1[K1]-1)],(S2-K2) [/b]类似。[/b]

所以我们可以在读入时就把A1 [/b],A2 [/b]的所有数全部减 1 [/b],计算时直接 S1*S2[/b]。[/b]

假设 S1*S2 [/b]的 S1 [/b]是 A1 [/b]序列中两个或两个以上元素的和, S2 [/b]类似。那么我们可以把 S1 [/b]拆成两个和 S11 [/b], S12 [/b];把 S2 [/b]拆成两个和 S21 [/b], S22 [/b]。则[/b]

S1*S2=(S11+S12)*(S21+S22)=S11*S21+S12*S21+S11*S22+S12*S22>S11*S21+S12*S22 ;[/b]

[/b]可见把它们分开消去更优。所以要这样一直拆分下去,直到某个和 S [/b]为一个元素的和。所以每次都在 A1[/b],A2 [/b]中选择某一序列的一个元素跟另外一个序列的一段(或一个)消去。[/b]

那么状态转移方程就变成了:[/b]

f[i,j]:=min{ f[i+1,q]+A1[i]*(Tj-Tq) | (j<q<=l2+1) [/b]

f[p,j+1]+(Si-Sp)*A2[j] | (i<p<=l1+1) }[/b]

[/b]这样为 O(L^3) [/b]。[/b]

假设A1[i][/b]与A2[/b]序列的一段 x->(y-1) [/b]一起消去。如下图,[/b]

A1[i]: [/b]□[/b]

i[/b]

A2[x]->A2[(y-1)]: [/b]□ [/b]□ [/b]□ [/b]□ [/b]…… [/b]□ [/b]□[/b]

x x+1 x+2 …… y-2 y-1[/b]

这个表示为 f[i,x]=f[i+1[/b],y]+A1[i]*(Tx-Ty)[/b]。[/b]

显然可以看做是 A1[i] [/b]跟 A2[x+1]->A2[y-1] [/b]一起消去然后A1[i][/b]再跟A2[x][/b]一起消去,而前者为 f[i,x+1] , [/b]后者为 A1[i]*A2[x] [/b];[/b]

[/b]所以还可以表示为 f[i,x]=f[i,x+1]+A1[i]*A2[x];[/b]

那么状态转移方程就变成了:[/b]

f[i,j]:=min{ f[i+1,j]+A1[i]*A2[j] //A1[/b]序列的i[/b]与A2[/b]序列从j[/b]开始的一段一起消去 [/b]

f[i,j+1]+A1[i]*A2[j] //A1[/b]序列从i[/b]开始的一段与A2[/b]序列的j[/b]一起消去[/b]

f[i+1,j+1]+A1[i]*A2[j] } //A1[/b]序列的i[/b]与A2[/b]序列的j[/b]一起消去[/b]

这样就是O(L^2)[/b]的了。[/b]

[/b]

4. [/b]注意事项[/b]

注意 f [/b]数组的初值![/b]

5. [/b]程序代码[/b]

SueMiller [/b](Pascal[/b])[/b]

var l1,l2:integer;[/b]

a1,a2:array[0..2010]of longint;[/b]

i,j:integer;[/b]

f:array[0..2010,0..2010]of longint;[/b]

[/b]

function min(a,b:longint):longint;[/b]

begin[/b]

if a<b then exit(a) else exit(b);[/b]

end;[/b]

[/b]

begin[/b]

assign(input,'Pk.in');reset(input);[/b]

assign(output,'Pk.out');rewrite(output);[/b]

[/b]

readln(l1,l2);[/b]

for i:=1 to l1 do begin read(a1[i]);dec(a1[i]);end;[/b]

for i:=1 to l2 do begin read(a2[i]);dec(a2[i]);end;[/b]

[/b]

filldword(f,sizeof(f)>>2,maxlongint);[/b]

f[l1+1,l2+1]:=0;[/b]

for i:=l1 downto 1 do[/b]

for j:=l2 downto 1 do[/b]

begin[/b]

f[i,j]:=min(min(f[i+1,j],f[i,j+1]),f[i+1,j+1])+a1[i]*a2[j];[/b]

end;[/b]

[/b]

writeln(f[1,1]);[/b]

[/b]

close(input);close(output);[/b]

end.[/b]

[/b]

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