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

来源:互联网 发布:疯狂联盟兵种数据 编辑:程序博客网 时间:2024/04/27 21:59

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

心情复杂,打了半天的题解死机一下全没了。。。
这题我讲一下思考过程,不想听的可以跳过。

  首先我们很容易想到列出f[i][j][k]表示已经走完前i-1层,走到第i层,A走j,B走k的方案数。然后我们先无脑暴力一波,直接枚举从上一层的j,k跳到这层的j'k',复杂度nm^4。60分都没有,明显不行。那么我们就致力于减少枚举的次数,最好能达到nm^2。  要减少,也就是说,我们目前枚举的有两个数是没用的,或者能替代掉,才能去。那么,对于上一层的位置j,k,明显是不能去掉的的,因为我们并不能确定当前位置的上一个状态。那么我们只能去掉对于当前第i层的枚举了。怎么替代呢,我们想想,如果我们必须枚举这一层,是因为我们不能确定,从上一层的j,k位置,走最优方案,到这一层是哪一个位置。但是明显,我们是可以不用确认的,因为我们对于每一个位置j',更新j',j'+1,j'-1(下一层),就可以把状态算上,  这什么意思呢?我举个例子:比如我们一开始更新了f[i][1][2],(j'=1,k'=2)f[i][1][3].....(i!=1),然后我们更新到f[i][1][3](j'=2,k'=3),此时更新的时候,已经把上一个状态累积进去了,用这种方法,我们就可以成功将dp复杂度缩小到nm^2.

所以容易得dp式子
f[i][j+1][k]=min(f[i][j+1][k],f[i][j][k]+c)(c即是参数,j

#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long ll;ll inf=1e15;int n,m;const int N=305;ll f[N][N];int a[N][N];int c;int main(){    freopen("room.in","r",stdin);    freopen("room.out","w",stdout);    scanf("%d%d%d",&n,&m,&c);    fo(i,1,n)    {        fo(j,1,m)        scanf("%d",&a[i][j]);    }    fo(i,1,m)    fo(j,1,i-1)f[i][j]=a[1][i]+a[1][j];    fo(i,2,n)    {        //memcpy(f[i],f[i-1],sizeof(f[i]));        fo(j,1,m)        fo(k,1,j-1)        {            if (j+1<=m)            f[j+1][k]=min(f[j+1][k],f[j][k]+c);            if (k+1<=m)            f[j][k+1]=min(f[j][k+1],f[j][k]+c);        }        fd(j,m,1)        fd(k,j-1,1)        {            if (j-1>=1)            f[j-1][k]=min(f[j-1][k],f[j][k]+c);            if (k-1>=1)            f[j][k-1]=min(f[j][k-1],f[j][k]+c);        }        fo(j,1,m)        fo(k,1,j-1)        f[j][k]+=a[i][j]+a[i][k];    }    ll ans=inf;    fo(i,1,m)    fo(j,1,i-1)ans=min(ans,f[i][j]);    printf("%lld\n",ans);}
0 0