题目源:https://vjudge.net/problem/POJ-1087
http://poj.org/problem?id=1087
模板源:https://blog.csdn.net/Adolphrocs/article/details/84368661
https://blog.csdn.net/Adolphrocs/article/details/84779661
https://blog.csdn.net/Adolphrocs/article/details/84779575
题解:源点和插头连一条边,插头和插座连一条边,转换器一边与插头连边,一边与插座连边,插座与汇点连边,流量均为1
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
#define MAXN 600
#define inf 100001000
int Map[MAXN][MAXN];//存图
int pre[MAXN];//记录当前点的前驱
int level[MAXN];//记录距离标号
int gap[MAXN];//gap常数优化
int NV, NE, Cnt;
map <string, int> idx;
//入口参数vs源点,vt汇点
int SAP(int vs, int vt){
memset(pre, -1, sizeof(pre));
memset(level, 0, sizeof(level));
memset(gap, 0, sizeof(gap));
gap[0] = vt;
int v, u = pre[vs] = vs, maxflow = 0, aug = inf;
while (level[vs] < vt) {
//寻找可行弧
for(v = 1; v <= vt; v++) {
if(Map[u][v] > 0 && level[u] == level[v] + 1){
break;
}
}
if(v <= vt){
pre[v] = u;
u = v;
if(v == vt){
aug = inf;
//寻找当前找到的一条路径上的最大流
for(int i = v; i != vs; i = pre[i]){
if(aug > Map[pre[i]][i]) aug = Map[pre[i]][i];
}
maxflow += aug;
//更新残留网络
for(int i = v; i != vs; i = pre[i]){
Map[pre[i]][i] -= aug;
Map[i][pre[i]] += aug;
}
u = vs;//从源点开始继续搜
}
}else {
//找不到可行弧
int minlevel = vt;
//寻找与当前点相连接的点中最小的距离标号
for (v = 1; v <= vt; v++){
if(Map[u][v] > 0 && minlevel > level[v]){
minlevel = level[v];
}
}
gap[level[u]]--;//(更新gap数组)当前标号的数目减1;
if (gap[level[u]] == 0) break;//出现断层
level[u] = minlevel + 1;
gap[level[u]]++;
u = pre[u];
}
}
return maxflow;
}
int main() {
int n, m, k, u, v, cap, T = 310;
while(~scanf("%d", &n)){
char x[50], y[50];
memset(Map, 0, sizeof(Map));
for(int i = 2; i <= n + 1; i++){
scanf("%s", x);
//printf("%d\n", i);
idx[x] = i;
Map[i][T] = 1;
}
scanf("%d", &m);
Cnt = n + m + 1;
for (int i = 1; i <= m; i++){
scanf("%s%s", x, y);
if (!idx[y]) idx[y] = (++Cnt);
//printf("%d %d\n", n + 1 + i, idx[y]);
idx[x] = n + 1 + i;
int u = idx[y];
Map[n + 1 + i][u] = 1;
Map[1][n + 1 + i] = 1;
}
scanf("%d",&k);
for (int i = 1; i <= k; i++){
scanf("%s%s", x, y);
if (!idx[x]) idx[x] = (++Cnt);
if (!idx[y]) idx[y] = (++Cnt);
//printf("%d %d\n", idx[x], idx[y]);
int s = idx[x];
int t = idx[y];
Map[s][t] = inf;
}
Cnt++;
for (int i = 1; i <= Cnt; i++){
Map[Cnt][i] = Map[T][i];
Map[i][Cnt] = Map[i][T];
}
printf("%d\n", m - SAP(1, Cnt));
}
return 0;
}
SAP+GAP邻接表
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
const int MAXN = 600;
const int MAXN_INT = (1 << 29);
const int inf = (1 << 29);
struct Edge{
int v, w, nxt;
};
struct node {
int in[MAXN],
out[MAXN],
Flow;
}a[MAXN];
bool isFind;
int head[MAXN];
Edge edge[MAXN];
int Map[MAXN][MAXN];
int dis[MAXN], gap[MAXN], ans[MAXN];
int P, n, m, ecnt, aug, maxFlow, k, F, D, Cnt;
map <string, int> idx;
void init(){
ecnt = maxFlow = 0;
memset(gap, 0, sizeof(gap));
memset(dis, 0, sizeof(dis));
memset(edge, 0, sizeof(edge));
memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int w){
edge[ecnt].v = v;
edge[ecnt].w = w;
edge[ecnt].nxt = head[u];
head[u] = ecnt++;
}
void Find(int s){
int dx, augc, minDis;
if(s == n){
isFind = true;
maxFlow += aug;
return;
}
augc = aug;
minDis = n - 1;
for(int i = head[s]; i + 1; i = edge[i].nxt){
if(edge[i].w > 0){
if(dis[s] == dis[edge[i].v] + 1){
aug = min(aug, edge[i].w);
Find(edge[i].v);
if(dis[1] >= n) return;
if(isFind){
dx = i;
break;
}
aug = augc;
}
minDis = min(minDis, dis[edge[i].v]);
}
}
if(!isFind){
gap[dis[s]]--;
if(gap[dis[s]] == 0) dis[1] = n;
dis[s] = minDis + 1;
gap[dis[s]]++;
}else{
edge[dx].w -= aug;
edge[dx ^ 1].w += aug;
}
}
int main(){
int T = 555;
while(scanf("%d", &n) != EOF){
init();
int i, j;
char x[50], y[50];
memset(Map, 0, sizeof(Map));
for(int i = 2; i <= n + 1; i++){
scanf("%s", x);
//printf("%d\n", i);
idx[x] = i;
Map[i][T] = 1;
}
scanf("%d", &m);
Cnt = n + m + 1;
for (int i = 1; i <= m; i++){
scanf("%s%s", x, y);
if (!idx[y]) idx[y] = (++Cnt);
//printf("%d %d\n", n + 1 + i, idx[y]);
idx[x] = n + 1 + i;
int u = idx[y];
Map[n + 1 + i][u] = 1;
Map[1][n + 1 + i] = 1;
}
scanf("%d",&k);
for (int i = 1; i <= k; i++){
scanf("%s%s", x, y);
if (!idx[x]) idx[x] = (++Cnt);
if (!idx[y]) idx[y] = (++Cnt);
//printf("%d %d\n", idx[x], idx[y]);
int s = idx[x];
int t = idx[y];
Map[s][t] = inf;
}
Cnt++;
for (int i = 1; i <= Cnt; i++){
Map[Cnt][i] = Map[T][i];
Map[i][Cnt] = Map[i][T];
}
n = Cnt;
gap[0] = Cnt;
for (int i = 1; i <= Cnt; i++)
for (int j = 1; j <= Cnt; j++){
if (Map[i][j]){
addEdge(i, j ,Map[i][j]);
addEdge(j, i, 0);
//printf("%d -> %d weight %d\n",i, j, Map[i][j]);
}
}
while(dis[1] < n){
isFind = 0;
aug = MAXN_INT;
Find(1);
}
printf("%d\n", m - maxFlow);
}
return 0;
}