POJ-2029 Get Many Persimmon Trees---二维树状数组+枚举

题目链接:

https://vjudge.net/problem/POJ-2029

题目大意:

有N棵树在一个n*m的田里,给出每颗树的坐标

用一个s*t的矩形去围,最多能围几棵树
思路:
用二维树状数组求区域和,也可以直接用二维前缀和求解
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<map>
 6 #include<set>
 7 #include<cmath>
 8 #include<algorithm>
 9 #define lowbot(i) (i&(-i))
10 using namespace std;
11 typedef long long ll;
12 const int maxn = 500 + 10;
13 int n, m, T, k, cases;
14 int tree[maxn][maxn];
15 void add(int x, int y, int d)
16 {
17     for(int i = x; i <= n; i += lowbot(i))
18     {
19         for(int j = y; j <= m; j += lowbot(j))
20         {
21             tree[i][j] += d;
22         }
23     }
24 }
25 int sum(int x, int y)
26 {
27     int ans = 0;
28     for(int i = x; i > 0; i -= lowbot(i))
29     {
30         for(int j = y; j > 0; j -= lowbot(j))
31         {
32             ans += tree[i][j];
33         }
34     }
35     return ans;
36 }
37 int Sum(int x1, int y1, int x2, int y2)
38 {
39     return sum(x2, y2) + sum(x1 - 1, y1 - 1) - sum(x1 - 1, y2) - sum(x2, y1 - 1);
40 }
41 int main()
42 {
43     while(cin >> k && k)
44     {
45         int x, y, s, t;
46         memset(tree, 0, sizeof(tree));
47         cin >> n >> m;
48         while(k--)
49         {
50             scanf("%d%d", &x, &y);
51             add(x, y, 1);
52         }
53         cin >> s >> t;
54         int ans = 0;
55         for(int i = 1; i + s - 1 <= n; i++)
56         {
57             for(int j = 1; j + t - 1 <= m; j++)
58             {
59                 int tot = Sum(i, j, i + s - 1, j + t - 1);
60                 ans = max(ans, tot);
61             }
62         }
63         cout<<ans<<endl;
64     }
65     return 0;
66 }

 

转载于:https://www.cnblogs.com/fzl194/p/8946975.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ - 3616是一个题目,题目描述如下: 给定一组区间,每个区间有一个权重,要求选择一些区间,使得这些区间的右端点都小于等于k,并且权重之和最大。请问最大的权重和是多少? 解决这个问题的思路是使用动态规划。首先,将区间按照左端点从小到大进行排序。然后,定义一个dp数组,dp[i]表示右端点小于等于i的所有区间所能得到的最大权重。 接下来,遍历每一个区间,对于每个区间i,将dp[i]初始化为区间i的权重。然后,再遍历i之前的每个区间j,如果区间j的右端点小于等于k,并且区间j的权重加上区间i的权重大于dp[i],则更新dp[i]为dp[j]加上区间i的权重。 最后,遍历整个dp数组,找到最大的权重和,即为所求的答案。 下面是具体的代码实现: ```cpp #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct interval{ int start, end, weight; }; interval intervals[10005]; int dp[10005]; int n, m, k; bool compare(interval a, interval b) { if (a.start == b.start) { return a.end < b.end; } else { return a.start < b.start; } } int main() { while(~scanf("%d %d %d", &n, &m, &k)) { memset(dp, 0, sizeof dp); for (int i = 0; i < m; i++) { scanf("%d %d %d", &intervals[i].start, &intervals[i].end, &intervals[i].weight); } sort(intervals, intervals + m, compare); for (int i = 0; i < m; i++) { dp[i] = intervals[i].weight; for (int j = 0; j < i; j++) { if (intervals[j].end <= k && dp[j] + intervals[i].weight > dp[i]) { dp[i] = dp[j] + intervals[i].weight; } } } int maxWeight = 0; for (int i = 0; i < m; i++) { maxWeight = max(maxWeight, dp[i]); } printf("%d\n", maxWeight); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值