2020年華中科技大學計算機科學與技術學院研究生入學考試複試專業實踐能力考覈試題——監控相機佈局問題

一、題目描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

二、解題思路

因爲我並沒有接觸和了解過提示中列舉出來的除了貪心算法之外的算法,所以我採用貪心算法來解決

  • GetDataFromTXT()函數

    • 將txt中的數據讀入哈希表,建立起攝像頭ID和覆蓋區域的映射
    • 建立一個當前仍沒有被覆蓋的點位集合,對於運行到這步的程序,也就是全部待監控點位的集合
  • Calculate()函數

    • 選出一個攝像頭,這個攝像頭可以覆蓋最多的監控盲區,即取每個由攝像頭ID映射出來的該攝像頭覆蓋區域集合和當前盲區集合的交集
    • 取所有交集中元素最多的那個攝像頭ID,作爲當前最優解
    • 維護當前盲點集合,從盲點集合中刪除最優解的攝像頭ID覆蓋的點位,即取當前盲點集合和這個集合的差集
    • 從哈希表中刪除當前最優解ID和其覆蓋區域的映射
      • 否則,問題退化爲“選出這樣一個攝像頭ID,即便這個攝像頭覆蓋了一些已覆蓋的點位,也沒有關係”
      • 但是這將導致計算時間嚴重的惡化,同時不影響輸出的結果
    • 輸出當前最優解到輸出文件

三、解題代碼

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <set>
#include <unordered_map>
using namespace std;

unordered_map<int, set<int>> CameraAndItsRange;
set<int> not_found, sln;
int how_many_elem, how_many_places;

void GetDataFromTXT()
{
    FILE *srcFile = fopen("../test01.txt", "r");
    if (!srcFile)
    {
        printf("test01.txt doesn't exist\n");
        exit(0);
    }
    fscanf(srcFile, "%d %d", &how_many_elem, &how_many_places);

    for (int i = 0; i < how_many_elem; i++)
    {
        int which_elem, how_many;
        fscanf(srcFile, "%d", &which_elem);
        fscanf(srcFile, "%d", &how_many);
        for (int j = 0; j < how_many; j++)
        {
            int which_place;
            fscanf(srcFile, "%d", &which_place);
            CameraAndItsRange[which_elem].insert(which_place);
        }
    }

    for (auto it = CameraAndItsRange.begin(); it != CameraAndItsRange.end(); it++)
        for (auto iter = it->second.begin(); iter != it->second.end(); iter++)
            not_found.insert(*iter);
    fclose(srcFile);
}
void Calculate()
{
    FILE *outFile = fopen("../Out1.txt", "w");
    if (!outFile)
    {
        printf("Out1.txt doesn't exist\n");
        exit(0);
    }
    while (!not_found.empty())
    {
        int best_camera; //找出覆蓋最多地點的攝像頭
        set<int> ItsPlaces;
        int How_not_found_places_covered = 0;

        for (auto iter = CameraAndItsRange.begin(); iter != CameraAndItsRange.end(); iter++)
        {
            set<int> tmp;
            set_intersection(iter->second.begin(), iter->second.end(), not_found.begin(), not_found.end(), inserter(tmp, tmp.begin()));
            if (tmp.size() > How_not_found_places_covered)
            {
                How_not_found_places_covered = tmp.size();
                best_camera = iter->first;
                ItsPlaces = tmp;
            }
        }
        CameraAndItsRange.erase(best_camera);
        set<int> tmp;
        set_difference(not_found.begin(), not_found.end(), ItsPlaces.begin(), ItsPlaces.end(), inserter(tmp, tmp.begin()));
        not_found = tmp;
        sln.insert(best_camera);
    }
    fprintf(outFile, "%d\n", sln.size());
    for (auto it = sln.begin(); it != sln.end(); it++)
        fprintf(outFile, "%d ", *it);
    fclose(outFile);
}
int main()
{
    printf("m1 Start!\n");
    GetDataFromTXT();
    printf("m1 GetDataFromTXT Finished!\n");
    Calculate();
    printf("m1 Calculate Finished!\n");

    printf("m1 Finished!\n\n");
    return 0;
}

四、運行結果

  真的燒CPU
在這裏插入圖片描述
運行出來的結果(部分):

test01.txt對應的解文件
在這裏插入圖片描述
test02.txt對應的解文件
在這裏插入圖片描述
test03.txt對應的解文件
在這裏插入圖片描述
test04.txt對應的解文件
在這裏插入圖片描述
test05.txt對應的解文件
在這裏插入圖片描述
完整的測試數據、題目PDF、源代碼、可執行文件、解文件,可以到我的Gitee查看


附言

我的解決方法我很清楚,絕對不是最優解,也肯定有很多錯誤,歡迎批評指正。


參考文獻:
[1] C++集合操作之集合交集:std::set_intersection
[2] 貪婪算法(集合覆蓋問題) - Python實現
[3] c++ set_union set_intersection使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章