// 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。