hdu5492 find the path dp
这是去年合肥的另一道签到。。。题目其实很简单。。。仔细想想范围就能推出来了,第一二维存位置,但显然不够,所以开第三维,由于空间限制只能在和以及平方和二选一,由于平方和太大,所以只能存和。然后dp的值如果存为方差*n的话,显然还需要一维存平方和,但仔细看看式子,如果和以及平方和知道了,也就知道方差了,而方差是很难处理的,事实上,当和固定的时候,平方和越小,方差*n也就越小,这个可以将式子展开得到,所以直接用dp的值来存平方和,先求出和为sum的情况下的最小平方和,然后再枚举sum就可以了。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define key_val ch[ch[rt[i]][1]][0] using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; int n,m; int a[40][40]; int dp[32][32][2200]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int casen=1; int T;cin>>T; while(T--){ scanf("%d%d",&n,&m); REP(i,1,n) REP(j,1,m) scanf("%d",&a[i][j]); REP(i,1,n) REP(j,1,m) REP(sum,0,1810) dp[i][j][sum]=INF; dp[1][1][a[1][1]]=a[1][1]*a[1][1]; REP(i,1,n){ REP(j,1,m){ REP(sum,a[i][j],1810){ if(i==1&&j==1) continue; dp[i][j][sum]=INF; if(i>1) dp[i][j][sum]=min(dp[i][j][sum],dp[i-1][j][sum-a[i][j]]+a[i][j]*a[i][j]); if(j>1) dp[i][j][sum]=min(dp[i][j][sum],dp[i][j-1][sum-a[i][j]]+a[i][j]*a[i][j]); } } } ll ans=INF; REP(sum,0,1810){ ll tmp=1LL*(n+m-1)*dp[n][m][sum]-sum*sum; ans=min(ans,tmp); } printf("Case #%d: %I64d\n",casen++,ans); } return 0; }
没有AC不了的题,只有不努力的ACMER!