http://acm.hdu.edu.cn/showproblem.php?pid=5492
化简该式得(n+m-1)*SA-sum*sum;式中SA为路径的平方和
逐项拆开得(n+m-2)*mp[i]*mp[i][j]-mp[i][j]*(S);式中S为mp[i][j]之前所有项和
然后对于所有的sum跑SPFA,相当于枚举所有sum的情况,能保证得到最优解
显然SPFA的常熟比DP大,这代码500ms过的
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int INF=0x7f7f7f7f;
const int maxn=38;
const int maxm=38*68;
int mp[maxn][maxn],dis[maxn][maxn][maxm];
int dir[2][2]={0,1,1,0};
int smp[maxn][maxn];
int n,m;
void spfa()
{
queue<int> q,p,r;
q.push(1);
p.push(1);
r.push(mp[1][1]);
memset(dis,-1,sizeof(dis));
dis[1][1][mp[1][1]]=smp[1][1]*(n+m-2);
int i,j,x,y,nx,ny,su,nsu;
while(!q.empty())
{
x=q.front();q.pop();
y=p.front();p.pop();
su=r.front();r.pop();
for(i=0;i<2;i++)
{
nx=x+dir[i][0];
ny=y+dir[i][1];
nsu=su+mp[nx][ny];
if(mp[nx][ny]==-1) continue;
if(dis[nx][ny][nsu]==-1||
dis[nx][ny][nsu]>dis[x][y][su]+smp[nx][ny]*(n+m-2)-2*mp[nx][ny]*su)
{
dis[nx][ny][nsu]=dis[x][y][su]+smp[nx][ny]*(n+m-2)-2*mp[nx][ny]*su;
q.push(nx);
p.push(ny);
r.push(nsu);
}
}
}
}
int main()
{
int i,j,t;
scanf("%d",&t);
int cas=1;
while(t--)
{
scanf("%d%d",&n,&m);
memset(mp,-1,sizeof(mp));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf("%d",&mp[i][j]);
smp[i][j]=mp[i][j]*mp[i][j];
}
spfa();
int ans=INF;
for(i=0;i<maxm;i++)
if(dis[n][m][i]!=-1&&dis[n][m][i]<ans)
ans=dis[n][m][i];
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}