【GDOI2017第二轮模拟day2】开房间

来源:互联网 发布:淘宝如何晒单 编辑:程序博客网 时间:2024/06/09 15:34

Description

A君与B君正在玩一款闯关游戏,游戏共有n关,每一关的目标只有一个:开房间。
每一关都会有m个房间(从1~m进行编号),A君与B君每关各打开一个房间即可过关,但两人不能打开同一个房间。
通过每一关后,m个房间会重新关上,在第i关打开第j个房间需要消耗t[i][j]的体力值。并且无论A君还是B君,除了第一关外,若上一关自己开了a号房间,这一关开了b号房间,则需要额外消耗K*|a-b|点体力值。
现在请你回答,两人过完全部n关后,所要消耗的体力值之和(两人消耗体力相加)最小能是多少。

Input

第一行三个整数n,m,K.
接下来n行每行m个整数,第i行第j个整数t[i][j]表示第i关开第j个房间需要消耗的体力值。

Output

仅一行一个整数表示答案。

Sample Input

3 3 10
2 13 4
4 3 2
16 4 3

Sample Output

28

Data Constraint

30%的数据:n,m <= 5
60%的数据:n,m <= 50
100%的数据:1 <= n,m <= 300 , 1 <= K,t[i][j] <= 10^6

题解

一开始比赛的时候想到用堆把一个n优化成log,但是后来发现是道套路题
我们考虑f[z,i,j]的贡献,容易发现是左上,右上,左下,右下四个方向的f[z-1,x,y]+k*曼哈顿距离+a[z,i]+a[z,j],最后两项可以最后再加上去,而前面的两项可以发现是一个二维的前缀和,所以我们可以从四个方向预处理前缀和,然后就可以O(1)算出当前位置的答案了
但是这样还是会超时,然后我们发现两个人的路径不会出现交叉的情况,那么我们强制i小于j,然后就可以把常数缩小一半,可以通过此题~

贴代码

var    f:array[0..305,0..305,0..305]of longint;    a,p1,p2,p3,p4:array[0..305,0..305]of longint;    i,j,k,l,n,m,x,y,z,ans:longint;function min(x,y:longint):longint;inline;begin    if x<y then exit(x) else exit(y);end;begin    assign(input,'room.in'); reset(input);    assign(output,'room.out'); rewrite(output);    readln(n,m,k);    for i:=1 to n do    begin        for j:=1 to m do read(a[i,j]);        readln;    end;    fillchar(f,sizeof(f),$7f);    for i:=1 to m do        for j:=1 to m do        if i<>j then f[1,i,j]:=a[1,i]+a[1,j];    fillchar(p1,sizeof(p1),$7f);    p2:=p1; p3:=p1; p4:=p1;    for z:=2 to n do    begin        for i:=1 to m-1 do            for j:=i+1 to m do            begin                if p1[i,j-1]<p1[i-1,j] then p1[i,j]:=p1[i,j-1]+k else p1[i,j]:=p1[i-1,j]+k;                if f[z-1,i,j]<p1[i,j] then p1[i,j]:=f[z-1,i,j];            end;        for i:=m-1 downto 1 do            for j:=i+1 to m do            begin                p2[i,j]:=f[z-1,i,j];                p2[i,j]:=min(p2[i,j],k+min(p2[i+1,j],p2[i,j-1]));            end;        for i:=1 to m-1 do            for j:=m downto i+1 do            begin                p3[i,j]:=f[z-1,i,j];                p3[i,j]:=min(p3[i,j],k+min(p3[i-1,j],p3[i,j+1]));            end;        for i:=m-1 downto 1 do            for j:=m downto i+1 do            begin                p4[i,j]:=f[z-1,i,j];                p4[i,j]:=min(p4[i,j],k+min(p4[i+1,j],p4[i,j+1]));            end;        for i:=1 to m-1 do            for j:=i+1 to m do            begin                //f[z,i,j]:=min(p1[i,j],min(p2[i,j],min(p3[i,j],p4[i,j])));                f[z,i,j]:=p4[i,j];                if p1[i,j]<f[z,i,j] then f[z,i,j]:=p1[i,j];                if p2[i,j]<f[z,i,j] then f[z,i,j]:=p2[i,j];                if p3[i,j]<f[z,i,j] then f[z,i,j]:=p3[i,j];                f[z,i,j]:=f[z,i,j]+a[z,i]+a[z,j];            end;    end;    ans:=maxlongint;    for i:=1 to m do        for j:=1 to m do        if i<>j then ans:=min(ans,f[n,i,j]);    writeln(ans);    close(input); close(output);end.
0 0
原创粉丝点击