采用EK算法解网络流经典题,本题构图思路比较明确。
//Unix会议室插座转换 //网络流-EK算法 //Time:47Ms Memory:1188K #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> using namespace std; #define MAX 505 #define MAXS 25 #define INF 0x3f3f3f3f int n,m,k; int s,t; int res[MAX][MAX]; //残留网络 int pre[MAX]; int len; //插头种类数 int no[MAX]; //插头下标编号 char trans[MAX][MAXS]; //插头名称 int getNum(char *str) //插头名称->编号 { for(int i = 0; i < len; i++) { if(!strcmp(trans[i], str)) return no[i]; } return -1; } bool bfs() { memset(pre,-1,sizeof(pre)); queue<int> q; q.push(s); pre[s] = 0; while(!q.empty()){ int cur = q.front(); q.pop(); for(int i = 1; i <= t; i++) { if(pre[i] == -1 && res[cur][i]) { pre[i] = cur; if(i == t) return true; q.push(i); } } } return false; } int EK() { int maxFlow = 0; while(bfs()) { int mind = INF; for(int i = t; i != s; i = pre[i]) mind = min(mind, res[pre[i]][i]); for(int i = t; i != s; i = pre[i]) { res[pre[i]][i] -= mind; res[i][pre[i]] += mind; } maxFlow += mind; } return maxFlow; } int main() { //freopen("in.txt", "r", stdin); memset(res,0,sizeof(res)); scanf("%d", &n); s = 0; t = n+1; //汇点在不断更新 len = 0; for(int i = 1; i <= n; i++) { no[len] = i; scanf("%s", trans[len++]); } scanf("%d", &m); t += m; int num[2]; char str[2][MAXS]; for(int i = n+1; i <= n+m; i++) { scanf("%s%s", str[0], str[1]); int num = getNum(str[1]); if(num == -1) { no[len] = num = t++; strcpy(trans[len++], str[1]); } res[s][i] = res[i][num] = 1; } scanf("%d", &k); for(int i = 0; i < k; i++) { scanf("%s%s", str[0], str[1]); for(int j = 0; j < 2; j++){ num[j] = getNum(str[j]); if(num[j] == -1) { no[len] = num[j] = t++; strcpy(trans[len++], str[j]); } } res[num[0]][num[1]] = INF; } //汇点已固定-更新汇点的邻接边 for(int i = 1; i <= n; i++) res[i][t] = 1; printf("%d\n", m - EK()); return 0; }