// 2604K 32MS G++ #include <cstdio> #include <map> #include <string> #include <queue> #include <cstring> using namespace std; #define MAX 230 map<string, int> deviceList; int receptacleNum; int deviceNum; int adapterNum; struct flowNode { int c; int f; }; int deviceInfo[MAX]; // indicate the ith device use which recep int gReceptacleUId; typedef struct flowNode flowNode; #define FLOW_MAX 500 #define INF 9999999 flowNode flowG[FLOW_MAX][FLOW_MAX]; // start from 1, and 1 is the s. 2 is the t int prev[FLOW_MAX]; int minFlow; queue<int> BFSQueue; char BFSFlag[FLOW_MAX]; char findAlternatingPath() { // printf("findAlternatingPath\n"); while(BFSQueue.size()) { BFSQueue.pop(); } memset(BFSFlag, 0, sizeof(BFSFlag)); BFSQueue.push(1); // begin from s(1) prev[1] = 0; // indicates the 1st node(s) in path has none prev BFSFlag[1] = 1; while(BFSQueue.size()) { int curId = BFSQueue.front(); BFSQueue.pop(); for (int i = 1 ; i < gReceptacleUId; i++) { // all nodes. s , t , recep and device // Check this first!!!!! if (flowG[curId][i].f < flowG[curId][i].c) { // if left some flow on this edge if (!BFSFlag[i]) { BFSFlag[i] = 1; // printf("BFS %d %d %d\n", i, flowG[curId][i].c, flowG[curId][i].f); //if (!prev[i]) { int curFlow = flowG[curId][i].c - flowG[curId][i].f; minFlow = minFlow < curFlow ? minFlow: curFlow; if (i == 2) { // reach t, find a alternating path! prev[2] = curId; return 1; } else { // go on BFS prev[i] = curId; BFSQueue.push(i); } //} } } } } return 0; } void solve() { // add the devices as nodes into flowG int deviceIdInFlowG = gReceptacleUId; for (int i = 1; i <= deviceNum; i++) { flowG[deviceIdInFlowG][2].c = 1; flowG[deviceIdInFlowG][2].f = 0; // every device connect to t with c = 1 int deviceUsedRecepId = deviceInfo[i]; flowG[deviceUsedRecepId][deviceIdInFlowG].c = INF; flowG[deviceUsedRecepId][deviceIdInFlowG].f = 0; // printf("set device %d %d\n", deviceUsedRecepId, deviceIdInFlowG); deviceIdInFlowG++; } gReceptacleUId = deviceIdInFlowG; // printf("%d\n", gReceptacleUId); // for (int i = 1; i < gReceptacleUId; i++) { // for (int j = 1; j < gReceptacleUId; j++) { // printf("<%d %d> ", flowG[i][j].c, flowG[i][j].f); // } // printf("\n"); // } int flowSum = 0; while(1) { minFlow = INF; memset(prev, 0, sizeof(prev)); if (!findAlternatingPath()) { // if no more alternating path, over. break; } //find an alternating path, do some adjust // printf("minFlow %d\n", minFlow); int curId = 2; int prevId = prev[curId]; while(prevId) { // printf("path %d -> %d\n", prevId, curId); if (flowG[prevId][curId].f != INF) { // INF + x == INF flowG[prevId][curId].f += minFlow; } if (flowG[curId][prevId].f != INF) { // INF -x == INF flowG[curId][prevId].f -= minFlow; } curId = prevId; prevId = prev[curId]; } flowSum += minFlow; } printf("%d\n", deviceNum - flowSum); } int main() { while(scanf("%d", &receptacleNum) != EOF) { gReceptacleUId = 3;// repceptacle begin from 3, 1 is the s, 2 is the t deviceList.clear(); char receptacleName[40] = ""; memset(deviceInfo, 0, sizeof(deviceInfo)); memset(flowG, 0, sizeof(flowG)); for (int i = 0; i < receptacleNum; i++) { scanf("%s", receptacleName); //receptacle id start from 3 flowG[1][gReceptacleUId].c = 1; flowG[1][gReceptacleUId].f = 0; deviceList.insert(pair<string, int>(receptacleName, gReceptacleUId++)); } scanf("%d", &deviceNum); char deviceName[40] = ""; for (int i = 1; i <= deviceNum; i++) { // device id begin from 1 scanf("%s %s", deviceName, receptacleName); if (deviceList.find(receptacleName) == deviceList.end()) { // if new receptacle // flowG[1][gReceptacleUId].c = 1; // flowG[1][gReceptacleUId].f = 0; deviceInfo[i] = gReceptacleUId;// deviceNum use the gReceptacleUId deviceList.insert(pair<string, int>(receptacleName, gReceptacleUId++)); } else { // if exist int rId = deviceList.at(receptacleName); deviceInfo[i] = rId; } // printf("A %d %d\n", i, deviceInfo[deviceNum]); } scanf("%d", &adapterNum); char recep1[40] = ""; char recep2[40] = ""; //adapter transform recep2 -> recep1 for (int i = 0; i < adapterNum; i++) { scanf("%s %s", recep1, recep2); int r1Id; int r2Id; // recep 1 is a new recep if (deviceList.find(recep1) == deviceList.end()) { r1Id = gReceptacleUId; // flowG[1][gReceptacleUId].c = 1; // flowG[1][gReceptacleUId].f = 0; deviceList.insert(pair<string, int>(recep1, gReceptacleUId++)); } else { r1Id = deviceList.at(recep1); } // recep 2 is a new recep if (deviceList.find(recep2) == deviceList.end()) { r2Id = gReceptacleUId; // flowG[1][gReceptacleUId].c = 1; // flowG[1][gReceptacleUId].f = 0; deviceList.insert(pair<string, int>(recep2, gReceptacleUId++)); } else { r2Id = deviceList.at(recep2); } // recep2 -> recep1 // printf("%d -> %d\n", r2Id, r1Id); flowG[r2Id][r1Id].f = 0; flowG[r2Id][r1Id].c = INF; } solve(); } }这道题刷的真累 ,先是本身题目解读就不是很直白,一度理解成一个插座可以插多个合适的设备,后来才发现应该是一个插座只能插一个合适的设备
然后又发现adapter上还可以继续插adapter, 即 a插座 插一个a->b 还可以再插一个 b->c, 就变成了c插座,
直接导致了原来想的二分图求最大权值匹配的想法落空。
后来还是搜了下,发现其实是一道最大流的题,不过要加上s和t,以及一些边,规则是这样的:
从s到已有的每个插座之间有一条c=1的流, 然后如果插座a通过adapter可以转换成插座b,那么从a到b之间有一条c=INF的流,
然后是设备D如果适配插座A, 那么A->D之间有一条c=INF的流, 最后,每个设备到t之间有一条c=1的流。
从s到每个插座的c=1流,表示了一个插座只能插一个合适设备,而从插座到适配设备间有c=INF流表示的是一种关系,只要遵从这种适配关系,就都可以流过,
因此是INF,而adpater转换也同样是这样, 从每个设备到t有c=1的流,表示的是每个设备都是独一无二的。
题目麻烦在于建立流图,不是很直观的直接给出,而是需要随着读取,进行预处理,来得到流图,
首先第一波的输入,其实可以建立s到插座之间的c=1流, 并且保存这次输入出现的插座(用了map来保存字符串和int之间的映射)
然后第二波输入,可以建立从设备到t的c=1流,以及插座到合适设备的c=INF流,注意的是,在第二波可能会出现新的插座类型,也要记录下来。
第三波,建立了插座之间通过adpater联系的c=INF流,同样注意可能会有新的插座类型。
其实这种中间还有些细节,其实图不是逐步建立的,而是是在上面3波信息都给出来以后,才建立的,一开始先只考虑插座和s之间的流,
设备和插座的关系先记录下来,在插座和s以及插座之间的流建立好以后,再将设备添加到图中,并建立相应的流。
建完流以后就简单了,直接最大流算法搞起就可以了,然后输出设备总数量 - 最大流数量
最大流算法流程还是记得不清楚,在BFS查找增广路时,
应该先看能从i到j是否有正向flow,如果有,才接下来考虑是否j之间的BFS是否已经遍历过并表示BFSFlag,不能倒过来,否则会漏。
比如 i -> t,如果先考虑BFSflag, 并将BFS[t]设为1,那么后面如果有别的1->2-t是合适的,就会被漏掉.
这种复合型条件的BFS一直掌握的不是很好.
还要注意貌似题目给的点的数目范围貌似小,数组要开的大点,不然re。