Description
某人要办个签证,办证处是一座 M 层的大楼,每层楼都有 N 个办公室,编号为1..N,每个办公室有一个签证员,签证需要让第 M 层的某个签证员盖章才有效。每个签证员都要满足下面三个条件之一才会给他盖章:
1. 这个签证员在1楼。
2. 这人的签证已经给这个签证员的正楼下(房间号相同)的签证员盖过章了。
3. 这人的签证已经给这个签证员的相邻房间(房间号相差1,楼层相同)的签证员盖过章了。
每个签证员盖章都要收取一定费用,这个费用不超过1000000000。找出费用最小的盖章路线,使签证生效。
Input
第1行两个整数 M 和 N 。 接下来M行每行 N 个整数,第i行第j个数表示第i层的第j个签证员收取的费用。
Output
输出最小的费用。
设f(i,j)表示从一楼到(i,j)的最小费用。则有一下几种:
一,直接从楼下上到楼上:
二,从左边过来:设前缀和sum[i][j]表示第i层楼1~j号房间收费总额。
三,从右过来:
最后作出决策:
扫描二维码关注公众号,回复:
2531682 查看本文章
另:据说此题还可以通过刷两次来使时间复杂度降为O(n*m)
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int MAXN=505;
const int MAXM=105;
const LL INF=2000000000000;
int N,M;
LL a[MAXM][MAXN],sum[MAXM][MAXN],f[MAXM][MAXN];
int main()
{
scanf("%d%d",&M,&N);
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
{
scanf("%lld",&a[i][j]);
sum[i][j]=sum[i][j-1]+a[i][j];
f[i][j]=INF;
}
for(int i=1;i<=N;i++)
f[1][i]=a[1][i];
for(int i=2;i<=M;i++)
for(int j=1;j<=N;j++)
{
LL t=f[i-1][j]+a[i][j];
for(int k=1;k<j;k++)
t=min(t,f[i-1][k]+sum[i][j]-sum[i][k-1]);
for(int k=j+1;k<=N;k++)
t=min(t,f[i-1][k]+sum[i][k]-sum[i][j-1]);
f[i][j]=t;
}
LL ans=INF;
for(int i=1;i<=N;i++)
ans=min(ans,f[M][i]);
printf("%lld",ans);
return 0;
}