黄金矿工

P2421 - 黄金矿工

Description

黄金矿工是一个经典的小游戏,它可以锻炼人的反应能力。该游戏中,可以通过“挖矿”获得积分并不断升级。玩家可以在线玩flash版黄金矿工,也可以下载后玩单机版黄金矿工。目前,黄金矿工小游戏有多个版本,例如黄金矿工双人版,黄金矿工单人版等。

Jimmy是一位黄金矿工,他所在的金矿是一个n*n的矩形区域(俯视),区域内有黄金、石头和TNT,由一个 n*n的矩阵描述。黄金的价值对应矩阵中的正值,石头的价值对应矩阵中的负值,TNT由0表示。换句话说,挖到黄金赚钱,石头亏损,如果挖到TNT就挂 了。

Jimmy租到的挖矿工具很特别,它的形状是一个长宽任意(均为正整数)的矩形,可以取走被该工具覆盖的矩形区域内的所有物品,但如果该区域内有 TNT,该工具将被炸毁,此时Jimmy将不得不赔偿矿主+∞元!!!需要注意的是,该工具只能在金矿范围内使用(即不得超出金矿边界),且租金为每次使 用十元。

现在,Jimmy想知道,如果他至多只有一次租用该工具的机会,他能获得的最大收益是多少。当然,如果Jimmy租用该工具无论如何都会亏损,他可以不租用,此时收益为0.

Input

第一行:一个整数n
接下来n行,每行n个整数(绝对值<100),为题目中所描述的矩阵。

Output

一个数,即Jimmy所能获得的最大收益。

Sample Input

3
0 -1 -1
0 -12 0
-19 0 0

Sample Output

0

Hint

【样例解释】
无论Jimmy怎么挖矿,挖到的不是石头,就是TNT,总之无论如何都会亏损,所以选择不租用工具,收益为0

【数据范围】
对于30%的数据:0<n<=10
对于60%的数据:0<n<=100
对于100%的数据:0<n<=300

首先考虑一维的做法:
f[i]表示选一个一i为尾的连续的序列,并且是和最大的。
很明显,f[i]=max(s[i]-s[j]),j<=i
但是这样太慢了,但仔细观察可以发现,这个j其实不需要枚举。
对于每一个i,它只和j有关系,所以就可以在枚举每一个i时看可不可以更新最优的决策,然后就可以O(n)解决了。
然后推广到二维,可以O(n^2)枚举列,然后在每一列O(n)跑个一维的,总复杂度O(n^3)。
注意要减10!!!

 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<ctime>
 6 #include<cmath>
 7 #include<string>
 8 #include<vector>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<cstring>
12 #include<iostream>
13 #include<algorithm>
14 #define LL long long
15 #define RG register
16 using namespace std;
17 LL a[310][310],f[310];
18 int main()
19 {
20   freopen("miner.in","r",stdin);
21   freopen("miner.out","w",stdout);
22   int n;
23   LL ans1=0;
24   scanf("%d",&n);
25   for(RG int i=1;i<=n;i++)
26     for(RG int j=1;j<=n;j++){
27       scanf("%lld",&a[i][j]);
28       if(a[i][j]==0) a[i][j]=-1999999999;
29     }
30   for(RG int i=1;i<=n;i++)
31     for(RG int j=1;j<=n;j++)
32       a[i][j]+=a[i][j-1];
33   for(int i=1;i<=n;i++)
34     for(int j=1;j<=n;j++)
35       a[i][j]+=a[i-1][j];
36   for(RG int i=0;i<=n;i++)
37     for(RG int j=i+1;j<=n;j++){
38       memset(f,0,sizeof(f));
39       int po=0;
40       LL ans=0;
41       for(RG int k=1;k<=n;k++){
42     f[k]=(a[k][j]-a[k][i])-(a[po][j]-a[po][i]);
43     if(a[k][j]-a[k][i]<ans) ans=a[k][j]-a[k][i],po=k;
44       }
45       for(int k=1;k<=n;k++)
46     ans1=max(ans1,f[k]);
47     }
48   ans1-=10;
49   if(ans1<0)ans1=0;
50   printf("%lld",ans1);
51   return 0;
52 }
原文地址:https://www.cnblogs.com/pantakill/p/6634061.html