CF GYM 100548 The Problem Needs 3D Arrays(2014ACM西安現場賽Problem C)

來源:互聯網
上載者:User

標籤:acm2014   acm-icpc   西安2014   

ProblemC. The Problem Needs 3D Arrays


Description

A permutation is asequence of integers p1, p2, . . . , pn,consisting of n distinct positive integers and each of them does notexceed n. Assume that r(S) of sequence S denotes the number ofinversions in sequence S (if i < j and Si > Sj,then the pair of (i, j) is called an inversion of S), l(S) ofsequence S denotes the length of sequence S. Given a permutation P oflength n, it’s your task to find a subsequence S of P with maximumr(S) / l(S). A subsequence of P is a sequence (pi1, pi2,. . . , pit) which satisfies that 0 < i1 <i2 < . . . < it ≤ n.


Input

The first line ofthe input gives the number of test cases, T. T test cases follow.

For each test case,the first line contains an integer n (1 ≤ n ≤ 100), the length ofthe permutation P. The second line contains n integers p1,p2, . . . , pn, which represents thepermutation P.


Output

For each test case,output one line containing “Case #x: y”, where x is the test casenumber (starting from 1) and y is the maximum r(S) / l(S).

Your answer will beconsidered correct if it is within an absolute error of 10?6of the correct answer.


Samples

Sample Input

Sample Output

1

5

3 4 2 5 1

Case #1: 1.250000000000



知識點:

最大密度子圖、最大權閉合圖、最小割。

題目大意:

給出1~n這n個正整數的一種排列P,要求在P中找出一個子序列S,使得子序列中包含的逆序數對數r(S)和子序列的長度l(S)的比值最大。輸出這個最大的比值r(S)/ l(S)。


解題思路:

可以將每個數看成圖中的點,將逆序對的關係轉換為圖中的邊。即構成了一個無向圖。範例可以轉換為:










現在要求的就是在圖中選取一些點,以及他們互相之間相連的邊,構成一個閉合子圖。使得圖中的邊數(逆序對數)與點數(選取的數字)的比值最大。這就是一個最大密度子圖的模型。範例的最佳選取方案,就是選擇圖中紅色標註的點和邊,共4個點5條邊,比值為1.25。

根據胡伯濤的論文《最小割模型在資訊學競賽中的應用》,可以使用0-1分數規劃的模型。根據分數規劃一般步驟,二分尋找答案。對於一個答案的猜測值g,將原圖轉化為網路G(V,E)的過程,即在原圖點集V的基礎上增加源s和匯t;將每條原無向邊替換為兩條容量為1的有向邊(u,v)和(v,u);增加串連源到原圖每個點的有向邊(s,v),容量為U;增加串連原圖每個點v到匯t的有向邊(v,t),容量為(U+2g?d[v])(其中d[v]是v點的度數)。求出網路的最小割(等於最大流),如果(U×n-最小割)/ 2 >=0,則猜測值g是可行的,放大g,繼續二分;若<0則是不可行的,縮小g,繼續二分。最後得出的就是可行的最大的g。即可求出最大的比值。


參考代碼:(未AC

#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <queue>#include <cmath>using namespace std;const double INF = 1 << 30;const double EPS = 1e-12;const int MAXN = 110;const int MAXM = 50010;struct Edge {    int u, v, next;    double c;    Edge() {}    Edge(int _u, int _v, double _c, int _next) : u(_u), v(_v), c(_c), next(_next) {}} edge[MAXM];int head[MAXN], cnt;bool visited[MAXN];int path[MAXN], d[MAXN], src, to;int n, m, nCase, cCase, p[MAXN], degree[MAXN];vector<pair<int, int> > E;void addEdge(int u, int v, double c) {    edge[cnt] = Edge(u, v, c, head[u]);    head[u] = cnt++;    edge[cnt] = Edge(v, u, 0, head[v]);    head[v] = cnt++;}bool bfs() {    memset(d, 0, sizeof(d));    queue<int> q;    q.push(src);    d[src] = 1;    while (!q.empty()) {        int u = q.front();        q.pop();        for (int i = head[u]; i != -1; i = edge[i].next) {            int v = edge[i].v;            if (edge[i].c && !d[v]) {                d[v] = d[u] + 1;                q.push(v);            }        }    }    return d[to];}double dfs(int x, double pf) {    if (x == to) return pf;    double ret = 0;    for (int i = head[x]; i != -1 && pf; i = edge[i].next) {        int v = edge[i].v;        if (edge[i].c && d[v] == d[x] + 1) {            double p = dfs(v, min(edge[i].c, pf));            edge[i].c -= p;            edge[i ^ 1].c += p;            ret += p;            pf -= p;        }    }    if (!ret) d[x] = -2;    return ret;}double dinic() {    double ret = 0.0;    while (bfs()) ret += dfs(src, INF);    return ret;}inline void buildEdge(double g) {    memset(head, -1, sizeof(head));    cnt = 0;    src = 0;    to = n + 1;    for (int i = 0; i < m; i++) {        addEdge(E[i].first, E[i].second, 1.0);        addEdge(E[i].second, E[i].first, 1.0);    }    for (int i = 1; i <= n; i++) {        addEdge(src, i, m * 1.0);        addEdge(i, to, m * 1.0 + 2.0 * g - degree[i]);    }}void init() {    E.clear();    memset(degree, 0, sizeof(degree));}void input() {    scanf("%d", &n);    for (int i = 1; i <= n; i++) {        scanf("%d", &p[i]);    }}inline bool check(double g) {    buildEdge(g);    double h = (1.0 * m * n - dinic()) / 2.0;    return h > 0;}void solve() {    for (int i = 1; i <= n; i++) {        for (int j = i+1; j <= n; j++) {            if (p[i] > p[j]) {                E.push_back(make_pair(i, j));                degree[i]++;                degree[j]++;            }        }    }    m = E.size();    if (m == 0) {        printf("Case #%d: %.12lf\n", ++cCase, 0);        return;    }    double l = 1.0 / n - EPS, r = m * 1.0 + EPS;    while (r - l > EPS) {        double mid = (l + r) / 2.0;        if (check(mid)) {            l = mid;        } else {            r = mid;        }    }    printf("Case #%d: %.12lf\n", ++cCase, l);}int main() {    scanf("%d", &nCase);    while (nCase--) {        init();        input();        solve();    }    return 0;}

歡迎討論指正。

CF GYM 100548 The Problem Needs 3D Arrays(2014ACM西安現場賽Problem C)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.