关闭

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

标签: 网络流最大稠密子图最大权闭合图
119人阅读 评论(0) 收藏 举报
分类:

题目链接

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 << endl

const 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

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:30147次
    • 积分:2670
    • 等级:
    • 排名:第13521名
    • 原创:254篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条