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

来源:互联网 发布:php完全自学手册下载 编辑:程序博客网 时间:2024/05/16 23:38

Description

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

Solution

直接60分DP的f[i][j][k]很明显。
但是要如何有优美的转移,我们知道在同一层走一个是k,但是我们在同一层 由(i-1,j),(i,j-1),(i+1,j),(i,j+1)转移过来,每次转移的时候+k。
那么这里只用m2就可以了
然后我们在最后再用a[i][j]加上每层开门的贡献就好了。

Code

#include<iostream>#include<string.h>#include<algorithm>#include<math.h>#include<stdio.h>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=307;int i,j,k,l,t,n,m,ans,pan,K,o;int f[maxn][maxn][maxn],a[maxn][maxn];int jue[maxn*2];int main(){    freopen("room.in","r",stdin);    freopen("room.out","w",stdout);//    freopen("fan.in","r",stdin);    scanf("%d%d%d",&n,&m,&K);    fo(i,1,n)fo(j,1,m)scanf("%d",&a[i][j]);    memset(f,127,sizeof(f));pan=f[0][0][0];    fo(i,1,m)fo(j,i+1,m)f[1][i][j]=a[1][i]+a[1][j];    fo(i,1,n)ans+=a[i][1]+a[i][2];    fo(i,2,n){        fo(j,1,m)fo(k,1,m)f[i][j][k]=f[i-1][j][k];        fo(j,1,m)fo(k,j+1,m)f[i][j][k]=min(f[i][j-1][k]+K,f[i][j][k]);        fod(j,m,1)fo(k,j+1,m)f[i][j][k]=min(f[i][j+1][k]+K,f[i][j][k]);        fo(j,1,m)fo(k,j+1,m)f[i][j][k]=min(f[i][j][k-1]+K,f[i][j][k]);        fo(j,1,m)fod(k,m,j+1)f[i][j][k]=min(f[i][j][k+1]+K,f[i][j][k]);        fo(j,1,m)fo(k,j+1,m)if(j!=k)f[i][j][k]+=a[i][j]+a[i][k];    }    fo(i,1,m)fo(j,i+1,m)if(i!=j)ans=min(ans,f[n][i][j]);    printf("%d\n",ans);}
1 0
原创粉丝点击