带权二分图最大匹配 P1500

Posted garen-wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带权二分图最大匹配 P1500相关的知识,希望对你有一定的参考价值。

带权二分图最大匹配 P1500

普通的二分图最大匹配的权值都是1,但是现在我们要解决带权的。

解决方法有两个:一个是匈牙利算法但是不会,另一个是最大费用最大流。

建图方式是这个样子:

  • 弄出源点和汇点。源点向男的连边,女的想汇点连边,流量为1,费用为0。
  • 满足条件的男的向女生连边,流量为1,费用为权值。

然后用EK算法,套上那个求最长路的SPFA就可以求最大费用最大流了。


但是这题建图有点坑:

  1. 名字都要统一大小写。
  2. 边只能从男的连向女的。这题歧视homosexual
  3. 有描述到的边的权值就是那个权值,没有描述到的边权值是1。
  4. 重边的权值看最后一条边。说好没重边的呢
  5. 两个人要连线,需要中间没有人,就是一个计算几何的问题。我这样写好像不对啊
  6. 有个人的名字叫做"Enda"。。。所以字符串要整个匹配。

代码:

/*************************************************************************
 @Author: Garen
 @Created Time : Mon 28 Jan 2019 05:43:04 PM CST
 @File Name: P1500.cpp
 @Description:
 ************************************************************************/
#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
using std::string;
const int maxn = 75;
const int INF = 0x3f3f3f3f;
// 邻接表
struct Edges {
    int next, to, weight, cost;
} e[1000005];
int head[maxn], tot = 1;
// 建图
int G[maxn][maxn];
std::pair<double,double> a[maxn];
std::map<string,int> mmp;
// 网络流
int last[maxn], pre[maxn];
int flow[maxn];
bool vis[maxn];
int dist[maxn];
int s, t;
int maxflow, maxcost;
int n;
double k;
void link(int u, int v, int w, int c) {
    e[++tot] = (Edges){head[u], v, w, c};
    head[u] = tot;
}
void add_edge(int u, int v, int c) {
    link(u, v, 1, c); link(v, u, 0, -c);
}
string lower(string str) {
    int len = str.length();
    for(int i = 0; i < len; i++) {
        if(str[i] >= ‘A‘ && str[i] <= ‘Z‘) str[i] += 32;
    }
    return str;
}
double dis(int u, int v) {
    return sqrt((a[u].first - a[v].first) * (a[u].first - a[v].first) + (a[u].second - a[v].second) * (a[u].second - a[v].second));
}
bool check(int u, int v) {
    if(dis(u, v) - k > 1e-5) return false;
    for(int i = 1; i <= 2 * n; i++) {
        if(i == u || i == v) continue;
        /*
        if(a[u].first < a[i].first && a[i].first < a[v].first)
            if(a[u].second < a[i].second && a[i].second < a[v].second) {
                double temp1 = (a[v].second - a[u].second) * (a[i].first - a[u].first);
                double temp2 = (a[v].first - a[u].first) * (a[i].second - a[u].second);
                if(fabs(temp1 - temp2) < 1e-5) return false;
            }
        */
        if(fabs(dis(u, i) + dis(i, v) - dis(u, v)) < 1e-5) return false;
    }
    return true;
}
bool spfa() {
    for(int i = 1; i <= t; i++) {
        flow[i] = last[i] = pre[i] = vis[i] = 0;
        dist[i] = -INF;
    }
    std::queue<int> q;
    dist[s] = 0; flow[s] = INF;
    q.push(s); vis[s] = true;
    while(!q.empty()) {
        int u = q.front(); q.pop(); vis[u] = false;
        for(int i = head[u]; i; i = e[i].next) {
            int v = e[i].to;
            if(e[i].weight > 0 && dist[u] + e[i].cost > dist[v]) {
                dist[v] = dist[u] + e[i].cost;
                last[v] = i;
                pre[v] = u;
                flow[v] = std::min(flow[u], e[i].weight);
                if(!vis[v]) {
                    q.push(v); vis[v] = true;
                }
            }
        }
    }
    return dist[t] != -INF;
}
void update() {
    maxflow += flow[t];
    maxcost += dist[t];
    for(int i = t; i != s; i = pre[i]) {
        e[last[i]].weight -= flow[t];
        e[last[i] ^ 1].weight += flow[t];
    }
}
void EK() {
    while(spfa()) update();
}
int main() {
    cin >> k;
    cin >> n;
    for(int i = 1; i <= n; i++)
        for(int j = n + 1; j <= n + n; j++)
            G[i][j] = 1;
    for(int i = 1; i <= 2 * n; i++) {
        string name;
        cin >> a[i].first >> a[i].second >> name;
        name = lower(name);
        mmp[name] = i;
    }
    string one, two; int temp;
    while(233) {
        cin >> one;
        if(one == "End") break;
        cin >> two >> temp;
        one = lower(one); two = lower(two);
        G[mmp[one]][mmp[two]] = G[mmp[two]][mmp[one]] = temp;
    }
    for(int i = 1; i <= n; i++)// fixed
        for(int j = n + 1; j <= 2 * n; j++)// fixed
            if(check(i, j)) {
                add_edge(i, j, G[i][j]);
                //cout << "shit" << endl;
            }
    s = 2 * n + 1; t = s + 1;
    for(int i = 1; i <= n; i++) add_edge(s, i, 0), add_edge(n + i, t, 0);// fixed
    EK();
    cout << maxcost << endl;
    return 0;
}

以上是关于带权二分图最大匹配 P1500的主要内容,如果未能解决你的问题,请参考以下文章

KM算法带权二分图完美匹配

二分图的最大匹配完美匹配和匈牙利算法

二分图的最大匹配完美匹配和匈牙利算法

(转)二分图的最大匹配完美匹配和匈牙利算法

Glorious Brilliance (最短路 + 带权二分图匹配)

费用流模板(带权二分图匹配)——hdu1533