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

来源:互联网 发布:齐天大圣象棋软件下载 编辑:程序博客网 时间:2024/04/28 12:07

Description

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

Data Constraint

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

Solution

我们设出状态f[i][j][k]表示当前在第i关,A在j,B在k且(j< k)的最小体力值。我们发现f[i][j][k]的转移同层之间相互独立,而且对于当前j,k,假设存在j’

Code

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const int maxn=305;ll f[maxn][maxn][maxn],a[maxn][maxn];ll n,m,i,t,j,k,l,x,y,z,ans,p;int main(){    freopen("room.in","r",stdin);freopen("room.out","w",stdout);    scanf("%lld%lld%lld",&n,&m,&p);    for (i=1;i<=n;i++)        for (j=1;j<=m;j++)            scanf("%lld",&a[i][j]);    memset(f,127,sizeof(f));    for (i=1;i<=m;i++)        for (j=i+1;j<=m;j++)            f[1][i][j]=a[1][i]+a[1][j];    for (i=2;i<=n;i++){        for (j=1;j<m;j++)            for (k=j+1;k<=m;k++)                f[i][j][k]=min(min(f[i][j-1][k],f[i][j][k-1])+p,f[i-1][j][k]);        for (j=m-1;j>=1;j--)            for (k=m;k>j;k--)                f[i][j][k]=min(f[i][j][k],min(f[i][j+1][k],f[i][j][k+1])+p);        for (j=1;j<m;j++)            for (k=j+1;k<=m;k++)                f[i][j][k]+=a[i][j]+a[i][k];    }    ans=1e18;    for (i=1;i<=m;i++)        for (j=i+1;j<=m;j++)            ans=min(ans,f[n][i][j]);    printf("%lld\n",ans);}
0 0
原创粉丝点击