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 ",cas++,ans); } return 0; }