2016级算法第二次上机-C.AlvinZH的儿时梦想——坦克篇

872 AlvinZH的儿时梦想----坦克篇

思路

简单题。仔细看题,题目意在找到直线穿过的矩形数最小,不能从两边穿过。那么我们只要知道每一行矩形之间的空隙位置就可以了。

如果这里用二维数组记住每一个空隙的位置,一是没有必要,二是记录了还要大量的处理才能得到答案。反正我是没想过要怎么处理。

可以发现,要得到本题的答案,只要找到空隙最多的哪个位置,我们取左边参考点,每一行的空隙位置我们可以记录到同一个数组里,即用A[pos]代表pos位置的直线有多少个空隙。但是发现总长度有点大,用数组是不可能了,有没有什么东西可以存下我这样的数对呢?

答案是map或轻便的pair。map的使用方法之前公邮里给大家发过了,不知道大家有没有好好学习。至于对组(pair),是一个稍微封装了一下的结构体模板,可以花一分钟看一下什么是对组。有着这个这题就简单了,两个值一个记录位置,一个记录出现次数,最后找到最大出现次数,n减去此数便可得到答案。具体可参考参考代码一。

非要这样做吗???我不会STL就做不了?

不是的,为什么非要把那么大的数当做索引呢?我就想把它当做数组的值,那下标是什么呢?答案是从0自增的一个计数变量。即A[cnt]记录空隙出现的位置,我们将它排序一下,相同位置会被放在一起,统计相同值的区间跨度一样可以找到空隙出现次数的最大值。具体见参考代码二。

分析

解法一使用map,时间复杂度将达到 \(O(NMlogNM)\)

解法二由于需要手动排序,时间复杂度一样是 \(O(NMlogNM)\)

参考代码一

//
// Created by AlvinZH on 2017/10/8.
// Copyright (c) AlvinZH. All rights reserved.
//

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int n, m, x;
    while(~scanf("%d %d", &n, &m))
    {
        map<int, int> sameSum;//统计相同和的个数

        for (int i = 0; i < n; ++i) {
            int sum = 0;
            for (int j = 0; j < m; ++j) {
                scanf("%d", &x);
                if(j == m - 1) continue;
                sum += x;
                sameSum[sum]++;
            }
        }
        int maxSame = 0;
        for(map<int, int>::iterator it = sameSum.begin(); it != sameSum.end(); it++)
            if(maxSame < it->second) maxSame = it->second;

        printf("%d\n", n - maxSame);
    }
}

参考代码二

/*
 Author: 蒋泳波(41)
 Result: AC    Submission_id: 343393
 Created at: Thu Oct 26 2017 14:48:19 GMT+0800 (CST)
 Problem: 872    Time: 106    Memory: 5292
*/

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1e6 + 10;

int a[maxn],cnt,x,n,m;

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        cnt = 0;
        for(int i = 1; i <= n; i++)
        {
            int now = 0;
            for(int j = 1; j < m; j++)
            {
                scanf("%d",&x);
                now += x;
                a[cnt++] = now;
            }
            scanf("%d",&x);
        }
        sort(a,a+cnt);
        int last = 0,ans = 0;
        a[cnt] = -1;//注意初始化值
        for(int i = 1; i <= cnt; i++)
        {
            if(a[i] != a[i-1])//找到分界位置
            {
                if(ans < i - last)
                    ans = i - last;
                last = i;
            }
        }
        printf("%d\n",n - ans);
    }
    return 0;
}
posted @ 2017-10-31 14:34  AlvinZH  阅读(394)  评论(0编辑  收藏  举报