每个数都看成一个节点,每个逆序对之间的节点连边,于是只需要求出这个图的最大密度子图,可以用最小割模型解决.
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> using namespace std; const double INF = 1e8; #define maxn 1511 #define maxm 2111111 #define eps 1e-10 #define type double int n, m, x, N; int s, t; struct Edge { int from, to,next; type cap,flow; void get(int u,int a,int b,type c,type d) { from = u; to = a; next = b; cap = c; flow = d; } }edge[maxm]; int tol; int head[maxn]; int gap[maxn],dep[maxn],pre[maxn],cur[maxn]; void init() { tol=0; memset(head,-1,sizeof(head)); } void add_edge(int u,int v,type w,type rw=0) { //cout << u << " " << v << " " << w << endl; edge[tol].get(u, v,head[u],w,0);head[u]=tol++; edge[tol].get(v, u,head[v],rw,0);head[v]=tol++; } type sap(int start,int end,int N) { memset(gap,0,sizeof(gap)); memset(dep,0,sizeof(dep)); memcpy(cur,head,sizeof(head)); int u=start; pre[u]=-1; gap[0]=N; type ans=0; while(dep[start]<N) { if(u==end) { type Min=INF; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) if(Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) { edge[i].flow+=Min; edge[i^1].flow-=Min; } u = start; ans+=Min; continue; } bool flag=false; int v; for(int i=cur[u];i !=-1;i=edge[i].next) { v=edge[i].to; if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]) { flag=true; cur[u]=pre[v]=i; break; } } if(flag) { u=v; continue; } int Min=N; for(int i=head[u];i!=-1;i=edge[i].next) if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min) { Min=dep[edge[i].to]; cur[u]=i; } gap[dep[u]]--; if(!gap[dep[u]]) return ans; dep[u]=Min+1; gap[dep[u]]++; if(u!=start) u=edge[pre[u]^1].to; } return ans; } int degree[maxn]; int num[maxn]; type f (type g) { init (); s = 0, t = n+1, N = n+2; double U = 1.0*m; for (int i = 1; i <= n; i++) { for (int j = 1; j < i; j++) { if (num[j] > num[i]) { add_edge (i, j, 1); add_edge (j, i, 1); } } } for (int i = 1; i <= n; i++) add_edge (s, i, U); for (int i = 1; i <= n; i++) add_edge (i, t, U+2*g-1.0*degree[i]); double ans = sap (s, t, N); ans = (U*n-ans)/2; return ans; } bool vis[maxn]; void dfs (int u) { vis[u] = 1; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (vis[v]) continue; if (edge[i].cap-edge[i].flow > 0 && edge[i].cap > 0) dfs (v); } } int main () { //freopen ("in.txt", "r", stdin); int tt, kase = 0; scanf ("%d", &tt); while (tt--) { scanf ("%d", &n); m = 0; memset (degree, 0, sizeof degree); for (int i = 1; i <= n; i++) { scanf ("%d", &num[i]); for (int j = 1; j < i; j++) { if (num[j] > num[i]) { degree[i]++; degree[j]++; m++; } } } double l = 0, r = 10000; int kk = 50; while (kk--) { double mid = (l+r)/2; double h = f (mid); if (h <= 0) r = mid; else l = mid; } printf ("Case #%d: %.7f\n", ++kase, l); } return 0; }