一、题目描述
二、解题思路
因为我并没有接触和了解过提示中列举出来的除了贪心算法之外的算法,所以我采用贪心算法来解决
-
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使用