LA7037-The Problem Needs 3D Arrays(最大稠密子图)

来源:互联网 发布:粒子群算法应用 编辑:程序博客网 时间:2024/06/05 16:53

题目链接

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5049

题意

给定一个序列,从里面选出x个数,其中的逆序对数为y,使y / x最大。

思路

将这些序列中的数看做点,其中存在逆序关系的(a[i], a[j])看做一条边,比如3 4 2 5 1。就可以建成如下的一张图:
这里写图片描述
那么问题就转化成了在图中选出若干个点,使这些点包含的边/这些点数最大。即最大稠密子图
最大稠密子图的求解参见:http://wenku.baidu.com/view/986baf00b52acfc789ebc9a9.html?from=search
其思路就是将最大稠密子图转化为最大权闭合图问题的求解。最大权闭合图求解步骤:
1. 新建源S和汇T,其中权值为正的结点,连一条S->该点的边,容量为该点权值。权值为负的结点,新建一条从该点->T的边,容量为该点权值的绝对值。
2. 对于原来的结点的边的关系,容量全部设为INF
3. 求该图的最小割
4. res = 权值为正的点的权值和 - 最小割

细节

二分的时候M也记得初始化,不然有可能根本没有进入循环,M也没有定义= =

代码

#include <iostream>#include <cstring>#include <stack>#include <vector>#include <set>#include <map>#include <cmath>#include <queue>#include <sstream>#include <iomanip>#include <fstream>#include <cstdio>#include <cstdlib>#include <climits>#include <deque>#include <bitset>#include <algorithm>using namespace std;#define PI acos(-1.0)#define LL long long#define PII pair<int, int>#define PLL pair<LL, LL>#define mp make_pair#define IN freopen("in.txt", "r", stdin)#define OUT freopen("out.txt", "wb", stdout)#define scan(x) scanf("%d", &x)#define scan2(x, y) scanf("%d%d", &x, &y)#define scan3(x, y, z) scanf("%d%d%d", &x, &y, &z)#define sqr(x) (x) * (x)#define pr(x) cout << #x << " = " << x << endl#define lc o << 1#define rc o << 1 | 1#define pl() cout << endlconst int maxn = 5000 + 500;const double INF = 0x3e3e3e3e;const double eps = 1e-8;int n;int a[105];struct Edge {    int from, to;    double cap, flow;    Edge(int u, int v, double c, double f) : from(u), to(v), cap(c), flow(f) {    }};struct Dinic {    int n, m, s, t;    vector<Edge> edges;    vector<int> G[maxn];    bool vis[maxn];    int cur[maxn], d[maxn];    void init() {        for (int i = 0; i < maxn; i++) G[i].clear();        edges.clear();    }    void addedge(int u, int v, double c) {        edges.push_back(Edge(u, v, c, 0));        edges.push_back(Edge(v, u, 0, 0));        m = edges.size();        G[u].push_back(m - 2);        G[v].push_back(m - 1);    }    bool bfs() {        memset(vis, 0, sizeof(vis));        queue<int> Q;        Q.push(s);        vis[s] = 1, d[s] = 0;        while (!Q.empty()) {            int x = Q.front(); Q.pop();            int _s = G[x].size();            for (int i = 0; i < _s; i++) {                Edge &e = edges[G[x][i]];                if (!vis[e.to] && e.cap - e.flow > eps) {                    vis[e.to] = 1;                    d[e.to] = d[x] + 1;                    Q.push(e.to);                }            }        }        return vis[t];    }    double dfs(int x, double a) {        if (x == t || a < eps) return a;        double flow = 0, f;        for (int &i = cur[x]; i < G[x].size(); i++) {            Edge &e = edges[G[x][i]];            if (d[e.to] == d[x] + 1) {                if (min(a, e.cap - e.flow) > eps) {                    f = dfs(e.to, min(a, e.cap - e.flow));                    e.flow += f;                    edges[G[x][i] ^ 1].flow -= f;                    flow += f;                    a -= f;                    if (a <= eps) break;                }            }        }        return flow;    }    double max_flow(int s, int t) {        this->s = s;        this->t = t;        double flow = 0;        while (bfs()) {            memset(cur, 0, sizeof(cur));            flow += dfs(s, INF);        }        return flow;    }};Dinic D;int tot, S, T;void buildgraph() {    int offset = n * (n - 1) / 2 + n;    S = offset + 2;    T = offset + 3;    tot = n + 1;    for (int i = 0; i < n; i++) {        for (int j = i + 1; j < n; j++) {            if (a[i] > a[j]) {                D.addedge(tot, a[i], INF);                D.addedge(tot++, a[j], INF);            }        }    }    for (int i = 1; i <= n; i++) D.addedge(i, T, 0);     for (int i = n + 1; i < tot; i++) D.addedge(S, i, 1);}bool judge(double x) {    for (int v = 1; v <= n; v++) {        for (int i = 0; i < D.G[v].size(); i++) {            Edge &e = D.edges[D.G[v][i]];            if (e.to == T) e.cap = x;        }    }    for (int i = 0; i < D.edges.size(); i++) {        Edge &e = D.edges[i];        e.flow = 0;    }    double flow = D.max_flow(S, T);    double pov = double(tot - n - 1);    return (pov - flow) >= eps;}double solve() {    D.init();    buildgraph();    int m = tot - n - 1;    double L = 0, R = double(m), M = (L + R) / 2;    while (R - L > eps) {        M = (L + R) / 2.0;        if (judge(M)) L = M;        else R = M;    }    return M;}int main() {    int T, kase = 0;    scan(T);    while (T--) {        scan(n);        for (int i = 0; i < n; i++) scan(a[i]);        double res = solve();        printf("Case #%d: %.6lf\n", ++kase, res);    }    return 0; }
0 0
原创粉丝点击