题目描述:
给定一张30*30的图,图上每个点的权值不超过30,让你求
(N+M−1)∑N+M−1i=1(Ai−Aavg)2的最小值?
队友将这个式子化成了求方差D[x]=E(x^2)-E(x);
我猜测是DP,分析一下,这个式子并不具有最优子结构,假设可以经过A和B
到达终点c,选取这两个点的方差的最小值,说明到达这两个点的序列最稳定,
假设A点是较优点,但是可能会出现,到达A点的最优序列加上c的序列,
没有到达A的某一个序列加上c的序列优(稳定)。
可以直接化简这个式子得到(A1^2+A2^2+A3^2+...+A[n+m-1]^2)*(n+m-1)-(A1+A2+A3+A4+...+A[n+m-1])^2;
观察一下我们可以维护和和平方和这两项,然后将到达某一个点的所有可能路径
,通过和来分类,d[x][y][k]表示到达x,y这个点和为k的最小平方和。
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <queue> #define maxn 31 #define LL long long #define inf 0x3f3f3f3f3f3f using namespace std; int ans; int d[maxn][maxn][1800]; int a[maxn][maxn]; int dir[2][2]={1,0,0,1}; int n,m; struct node { int x,y,k; }; void init() { for(int i=0;i<maxn;i++) for(int j=0;j<maxn;j++) for(int k=0;k<1800;k++) d[i][j][k]=inf; } void spfa() { int visit[maxn][maxn]; memset(visit,0,sizeof(visit)); queue <node> que; node start; start.x=1; start.y=1; start.k=a[1][1]; d[1][1][a[1][1]]=a[1][1]*a[1][1]; que.push(start); visit[1][1]=1; while(!que.empty()) { node next,cur=que.front(); que.pop(); for(int i=0;i<2;i++) { int x,y,k; next.x=x=cur.x+dir[i][0]; next.y=y=cur.y+dir[i][1]; next.k=k=cur.k+a[x][y]; if(next.x>=1 && next.x<=n && next.y>=1 && next.y<=m) { int temp=d[cur.x][cur.y][cur.k]+a[x][y]*a[x][y]; if(temp<d[x][y][k]) { d[x][y][k]=temp; if(visit[x][y]==1) continue; que.push(next); visit[1][1]=1; } } } } } int main() { // freopen("test.txt","r",stdin); //freopen("out.txt","w",stdout); int t; scanf("%d",&t); int cas = 0; while(t --) { init(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); //work(); spfa(); ans=inf; for(int k=0;k<=30*59;k++) { if(d[n][m][k]==inf) continue; int temp=(n+m-1)*d[n][m][k]-k*k; if(temp<=ans && temp>=0) ans=temp; } printf("Case #%d: %d ",++cas,ans); } return 0; }