poj-1087

17 篇文章 0 订阅
11 篇文章 0 订阅
// 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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值