CF GYM 100548 The Problem Needs 3D Arrays(2014ACM西安现场赛Problem C)
来源:互联网 发布:用友软件客服电话 编辑:程序博客网 时间:2024/05/18 00:36
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)
- CF GYM 100548 The Problem to Make You Happy(2014ACM西安现场赛Problem H)
- CF GYM 100548 Last Defence(2014ACM西安现场赛Problem K)
- CF GYM 100548 International Collegiate Routing Contest(2014ACM西安现场赛Problem I)
- CF GYM 100548 Color(2014ACM西安现场赛Problem F)
- CF GYM 100548 Color(2014ACM西安现场赛Problem F)
- 2014年西安区域赛C The Problem Needs 3D Arrays
- CF GYM 100548 Built with Qinghuai and Ari Factor(2014ACM西安现场赛Problem A)
- CF GYM 100548 International Collegiate Routing Contest(2014ACM西安现场赛Problem I)不懂提
- [最大密度子图 最小割] ACM 2014 Xian C The Problem Needs 3D Arrays
- 2014-2015 ACM-ICPC, Asia Xian Regional Contest C – The Problem Needs 3D Arrays(最大密度子图)
- UVAlive 7037 - The Problem Needs 3D Arrays(网络流‘最大密度子图)
- UVALive 7037 The Problem Needs 3D Arrays(最大密度子图)
- UVALive 7037 The Problem Needs 3D Arrays(网络流)
- LA7037-The Problem Needs 3D Arrays(最大稠密子图)
- Uvalive 7037 The Problem Needs 3D Arrays(最大密度子图)
- Uvalive 7037 The Problem Needs 3D Arrays (最大密集子图)
- Codeforces Gym 100548G The Problem to Slow Down You (Palindromic Tree 或 Hash水过) 2014西安现场赛G题
- 我所理解的设计模式(C++实现)——享元模式(Flyweight Pattern)
- linux开发环境搭建
- 我所理解的设计模式(C++实现)——外观模式(Facade Pattern)
- Android中RelativeLayout各个属性
- 细说php 第二版(章节+视频+项目+练习题+源码)
- CF GYM 100548 The Problem Needs 3D Arrays(2014ACM西安现场赛Problem C)
- 我所理解的设计模式(C++实现)——装饰者模式(Decorator Pattern)
- HashMap&HashSet Code Analyse
- select、poll、epoll之间的区别总结[整理]
- 学术休假期 项目1-动态链表体验6
- 运用快排函数
- N - Little Girl and Maximum Sum——贪心
- Hive中不走MapReduce的查询
- Broadcast Intent实现的四个步骤