费用流
最小费用最大流:在流量最大的前提下,总费用最小。
难点在于建图。
模板如下:
HDU 3376 Matrix Again
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxv = 1e+6;
const int maxe = 1e+7;
typedef int Type;
const Type INF = 0x3f3f3f3f;
struct Edge {
int u, v;
Type cap, flow, cost;
Edge() {}
Edge(int u, int v, Type cap, Type flow, Type cost) {
this->u = u;
this->v = v;
this->cap = cap;
this->flow = flow;
this->cost = cost;
}
};
struct MCFC {
int n, m, s, t;
Edge edges[maxe];
int first[maxv];
int next[maxe];
int inq[maxv];
Type d[maxv];
int p[maxv];
Type a[maxv];
int Q[maxe];
void init(int n) {
this->n = n;
memset(first, -1, sizeof(first));
m = 0;
}
void AddEdge(int u, int v, Type cap, Type cost) {
edges[m] = Edge(u, v, cap, 0, cost);
next[m] = first[u];
first[u] = m++;
edges[m] = Edge(v, u, 0, 0, -cost);
next[m] = first[v];
first[v] = m++;
}
bool BellmanFord(int s, int t, Type &flow, Type &cost) {
for (int i = 0; i < n; i++) d[i] = INF;
memset(inq, false, sizeof(inq));
d[s] = 0; inq[s] = true; p[s] = 0; a[s] = INF;
int front, rear;
Q[rear = front = 0] = s;
while (front <= rear) {
int u = Q[front++];
inq[u] = false;
for (int i = first[u]; i != -1; i = next[i]) {
Edge& e = edges[i];
if (e.cap > e.flow && d[e.v] > d[u] + e.cost) {
d[e.v] = d[u] + e.cost;
p[e.v] = i;
a[e.v] = min(a[u], e.cap - e.flow);
if (!inq[e.v]) {Q[++rear] = e.v; inq[e.v] = true;}
}
}
}
if (d[t] == INF) return false;
flow += a[t];
cost += d[t] * a[t];
int u = t;
while (u != s) {
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
u = edges[p[u]].u;
}
return true;
}
Type Mincost(int s, int t) {
Type flow = 0, cost = 0;
while (BellmanFord(s, t, flow, cost));
return cost;
}
}H;
int mapp[610][610];
int main() {
int n, u, v, w;
freopen("in.txt", "r", stdin);
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%d", &mapp[i][j]);
int s = 0, t = 2*n*n-1;
H.init(t+1);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
H.AddEdge(i*n+j, i*n+j+n*n, 1, -mapp[i][j]);
if (j != n-1)
H.AddEdge(i*n+j+n*n, i*n+j+1, 1, 0);
if (i != n-1)
H.AddEdge(i*n+j+n*n, i*n+j+n, 1, 0);
}
}
H.AddEdge(s, n*n, 1, 0);
H.AddEdge(n*n-1, t, 1, 0);
printf("%d\n", -H.Mincost(s, t));
}
return 0;
}
hdu 3718 Similarity
给出A, B两个分别由k不同字符组成的长度相同的字符串,现在把B中的每种字符变成A中含有的某种字符,(不能变成相同的A),求最多能有多少个字符匹配。
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef int Type;
const int maxv = 1e+5;
const int maxe = 1e+7;
const int INF = 0x3f3f3f3f;
struct Edge {
int u, v;
Type cap, flow, cost;
Edge() {}
Edge(int u, int v, Type cap, Type flow, Type cost) {
this->u = u;
this->v = v;
this->cap = cap;
this->flow = flow;
this->cost = cost;
}
};
struct MCFC {
int n, m, s, t;
Edge edges[maxe];
int first[maxv];
int next[maxe];
int inq[maxv];
Type d[maxv];
int p[maxv];
Type a[maxv];
int Q[maxe];
void init(int n) {
this->n = n;
memset(first, -1, sizeof(first));
m = 0;
}
void AddEdge(int u, int v, Type cap, Type cost) {
edges[m] = Edge(u, v, cap, 0, cost);
next[m] = first[u];
first[u] = m++;
edges[m] = Edge(v, u, 0, 0, -cost);
next[m] = first[v];
first[v] = m++;
}
bool BellmanFord(int s, int t, Type &flow, Type &cost) {
for (int i = 0; i < n; i++) d[i] = INF;
memset(inq, false, sizeof(inq));
d[s] = 0; inq[s] = true; p[s] = 0; a[s] = INF;
int front, rear;
Q[rear = front = 0] = s;
while (front <= rear) {
int u = Q[front++];
inq[u] = false;
for (int i = first[u]; i != -1; i = next[i]) {
Edge& e = edges[i];
if (e.cap > e.flow && d[e.v] > d[u] + e.cost) {
d[e.v] = d[u] + e.cost;
p[e.v] = i;
a[e.v] = min(a[u], e.cap - e.flow);
if (!inq[e.v]) {Q[++rear] = e.v; inq[e.v] = true;}
}
}
}
if (d[t] == INF) return false;
flow += a[t];
cost += d[t] * a[t];
int u = t;
while (u != s) {
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
u = edges[p[u]].u;
}
return true;
}
Type Mincost(int s, int t) {
Type flow = 0, cost = 0;
while (BellmanFord(s, t, flow, cost));
return cost;
}
}H;
char A[10000 + 10], B[5], C[10000 + 10], vis[2][52 + 10];
int mapp[26 + 10][26 + 10];
int main() {
int tcase, n, m, k;
//freopen("in.txt", "r", stdin);
scanf("%d", &tcase);
while (tcase--) {
scanf("%d%d%d", &n, &k, &m);
for (int i = 0; i < n; i++) {
scanf("%s", B);
A[i] = B[0];
}
while (m--) {
int s = 52, t = s+1;
H.init(t+1);
memset(mapp, 0, sizeof(mapp));
for (int i = 0; i < n; i++) {
scanf("%s", B);
mapp[A[i] - 'A'][B[0] - 'A']++;
C[i] = B[0];
}
for (int i = 0; i < 26; i++) {
for (int j = 0; j < 26; j++) {
if (mapp[i][j]) {
H.AddEdge(i, j+26, 1, -mapp[i][j]);
}
}
}
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; i++) {
int a = A[i] - 'A', b = C[i]-'A'+26;
if (!vis[0][a]) {
vis[0][a] = 1;
H.AddEdge(s, A[i] - 'A', 1, 0);
}
if (!vis[1][b]) {
vis[1][b] = 1;
H.AddEdge(C[i]-'A'+26, t, 1, 0);
}
}
double len = n * 1.0;
printf("%.4f\n", -H.Mincost(s, t)*1.0/len);
}
}
return 0;
}