Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
Re:网络流不会,但是回溯法可以AC!In Reply To:网络流不会,但是回溯法可以AC! Posted by:zoujing1978 at 2017-03-20 12:39:42 > 这题目我用回溯法AC了,WA了五六次,靠! /* 题意:房间里N个通了电的插座,有M种电器,每种电器只有插在对应类型的插座上才能正常工作。现在有K个转换器,能将一种类型的插座转换成另一种类型的插座。 利用这K个转换器和N个通电插座,使尽量多的电器能够正常通电工作(题目要求输出最少能使多少台电器不工作的数目)。 */ #include <iostream> #include <fstream> #include <string> #include <cstdio> #include <map> using namespace std; struct Plug // 电器上的插头类型 { int recep; // 插头需要的插座类型 bool* list; // 使用适配器后可以匹配的插座类型 }; struct Adapter // 适配器类型 { int recep; // 插座类型 int plug; // 插头类型 }; class POJ1087 { protected: int numReceps; // 插座的数量 int numPlugs; // 电器上的插头的数量 int numAdapts; // 适配器数量 Plug* plugs; // 电器的插座数组 Adapter* adapts; // 适配器数组 bool* canUse; // 某个插座能否使用 int* matchPlug; // matchPlug[i]表示最终与电器插头i匹配的插座编号 int* matchRecep; // matchRecep[i]表示最终插在插座i上的电器插头的编号 map<int, string> mapId2Name; map<string, int> mapName2Id; void Init(); // 初始化 void UseAdapter(int i); // 插头i使用适配器后,可以匹配的插座类型 bool Backtrack(int node); // 针对电器插头node进行搜索 public: POJ1087(); ~POJ1087(); void InputAndAlloc(int numReceps); // 输入某个测试用例的插座名称、插头名称、适配器名称信息 int Solve(); }; POJ1087::POJ1087() { this->numAdapts = 0; this->numReceps = 0; this->numPlugs = 0; plugs = NULL; adapts = NULL; canUse = NULL; matchPlug = NULL; matchRecep = NULL; } POJ1087::~POJ1087() { for (int i = 0; i < numPlugs; i++) { delete[] plugs[i].list; } delete[] plugs; delete[] adapts; delete[] canUse; delete[] matchPlug; delete[] matchRecep; } // 电器插头i使用适配器后,可以匹配的插座类型。这个方法值得回味 void POJ1087::UseAdapter(int i) { // 电器插头i本身与自身所需要的插座肯定匹配 plugs[i].list[plugs[i].recep] = true; // 由于适配器可以插入其他的适配器,所以使用一个适配器后,又重新搜索 bool flag = false; do { flag = false; // 遍历所有的适配器 for (int j = 0; j < numAdapts; j++) { // 如果电器插头i通过连接某些适配器后,能匹配适配器j的插座,并且电器插头i与适配器j的插头还没建立转换关系 if (plugs[i].list[adapts[j].recep] && !plugs[i].list[adapts[j].plug]) { flag = true; plugs[i].list[adapts[j].plug] = true; // 将电器插头i与适配器j的插头建立转换关系 } } } while (flag); // 只要为电器插头i找到了一个适配器,还需要重新搜索,直到为电器插头i找到所有 } // 针对电器插头node进行搜索 bool POJ1087::Backtrack(int node) { // 遍历所有的插座 for (int j = 0; j < numReceps; j++) { // 如果电器插头node与插座可以匹配(可以通过适配器),而且插座j可用 if (plugs[node].list[j] && canUse[j]) { if (matchRecep[j] == -1) // 如果电器插头node与插座j尚未匹配 { // 建立电器插头node与插座j的匹配关系 matchRecep[j] = node; matchPlug[node] = j; return true; } else { // 将插座j原先的匹配的电器插头存放在save中 int save = matchRecep[j]; // 将插座j原先的匹配的插头换成node尝试一下,并取消电器插头save所匹配的插座 matchRecep[j] = node; matchPlug[node] = j; matchPlug[save] = -1; // 设置插座j已经使用 canUse[j] = false; // 递归递归, if (Backtrack(save)) { return true; } // 恢复回溯前的状态 canUse[j] = true; matchPlug[save] = j; matchPlug[node] = -1; matchRecep[j] = save; } } } return false; } // 输入某个测试用例的插座名称、插头名称、适配器名称信息 void POJ1087::InputAndAlloc(int numReceps) { mapId2Name.clear(); mapName2Id.clear(); this->numReceps = numReceps; // 插座数量 matchRecep = new int[numReceps]; // 读取插座的名称,建立名称数组 for (int i = 0; i < numReceps; i++) { string name = ""; cin >> name; mapId2Name[i] = name; mapName2Id[name] = i; } cin >> numPlugs; canUse = new bool[numReceps]; matchPlug = new int[numPlugs]; plugs = new Plug[numPlugs]; // 读取电器插头的名称,建立插头数组,电器的名称其实没有用 for (int i = 0; i < numPlugs; i++) { string name = ""; cin >> name >> name; if (mapName2Id.find(name) == mapName2Id.end()) { mapName2Id[name] = mapName2Id.size(); mapId2Name[mapId2Name.size()] = name; } plugs[i].recep = mapName2Id[name]; } cin >> numAdapts; adapts = new Adapter[numAdapts]; // 读取适配器名称,创建适配器数组 for (int i = 0; i < numAdapts; i++) { string name = ""; cin >> name; if (mapName2Id.find(name) == mapName2Id.end()) { mapName2Id[name] = mapName2Id.size(); mapId2Name[mapId2Name.size()] = name; } adapts[i].recep = mapName2Id[name]; cin >> name; if (mapName2Id.find(name) == mapName2Id.end()) { mapName2Id[name] = mapName2Id.size(); mapId2Name[mapId2Name.size()] = name; } adapts[i].plug = mapName2Id[name]; for (int i = 0; i < numPlugs; i++) { plugs[i].list = new bool[mapId2Name.size()]; } } } void POJ1087::Init() { for (int i = 0; i < numPlugs; i++) { for (int j = 0; j < mapId2Name.size(); j++) { plugs[i].list[j] = false; } matchPlug[i] = -1; } for (int i = 0; i < numReceps; i++) { matchRecep[i] = -1; canUse[i] = true; } } int POJ1087::Solve() { Init(); // 初始化 // 遍历所有的电器插头 for (int i = 0; i < numPlugs; i++) { // 计算电器插头i使用适配器后,可以匹配的插座类型 UseAdapter(i); } int i = 0; while (i < numPlugs) // 如果还没遍历完所有的电器插头 { // 遍历所有的插座 for (int j = 0; j < numReceps; j++) { canUse[j] = true; // 设置插座j已经被占用 // 如果插头i还没有匹配的插座 if (matchPlug[i] == -1 && Backtrack(i)) { i = 0; } else { i++; } } } // 统计哪些电器插头没有匹配的插座 int min = 0; for (int i = 0; i < numPlugs; i++) { if (matchPlug[i] == -1) { min++; } } return min; } int main() { int numReceps = 0; while (cin >> numReceps) { POJ1087 obj; obj.InputAndAlloc(numReceps); cout << obj.Solve() << "\n"; } return 0; } Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator