1176:Planning Rolling Blackouts

問題文
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1176&lang=jp
































メモ化再帰した。再帰関数の引数は左上の位置と右下の位置+1。
配列uは累積和を計算しておいた。

#include<iostream>
#include<algorithm>
#define f first
#define s second
#define INF (1<<29)
using namespace std;

typedef pair<int,int> P;

int h,w,s,u[34][34];
P memo[34][34][34][34];

P rec(int x1,int y1,int x2,int y2){
	
	if(memo[x1][y1][x2][y2]!=P(0,INF))return memo[x1][y1][x2][y2];
	if(u[h-1][w-1]-(u[y2-1][x2-1]-u[y2-1][x1-1]-u[y1-1][x2-1]+u[y1-1][x1-1])>s)return P(0,INF);
	P res=P(1,s-(u[h-1][w-1]-(u[y2-1][x2-1]-u[y2-1][x1-1]-u[y1-1][x2-1]+u[y1-1][x1-1])));
	
	for(int i=y1+1;i<y2;i++){
		P a=rec(x1,y1,x2,i);
		P b=rec(x1,i,x2,y2);
		res=max(res,P(a.f+b.f,min(a.s,b.s)));
	}
	
	for(int i=x1+1;i<x2;i++){
		P a=rec(x1,y1,i,y2);
		P b=rec(i,y1,x2,y2);
		res=max(res,P(a.f+b.f,min(a.s,b.s)));
	}
	
	return memo[x1][y1][x2][y2]=res;
}

int main(void){
	
	while(cin >> h >> w >> s,h++|w++|s){
		
		fill(u[0],u[34],0);
		
		for(int i=0;i<34;i++)
			for(int j=0;j<34;j++)
				for(int k=0;k<34;k++)
					for(int l=0;l<34;l++)memo[i][j][k][l]=P(0,INF);
		
		for(int i=1;i<h;i++)
			for(int j=1;j<w;j++)cin >> u[i][j];
		
		for(int i=1;i<h;i++)
			for(int j=1;j<w;j++)
				u[i][j]+=u[i-1][j]+u[i][j-1]-u[i-1][j-1];
		
		P ans=rec(1,1,w,h);
		cout << ans.f << " " << ans.s << endl;
	}
	return 0;
}