思路:将所有逆序对连边,就是最大密度子图问题,参照论文~
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 8010;
const int maxm = 1000010;
const int INF = 1e9;
const double eps = 1e-12;
struct Edge
{
int to,next;
double cap,flow;
}edge[maxm];
int tot;
int head[maxn];
int gap[maxn],dep[maxn],cur[maxn],q[maxn];
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,double w,double rw = 0)
{
edge[tot].to = v;
edge[tot].cap=w;
edge[tot].flow = 0;
edge[tot].next = head[u];
head[u]=tot++;
edge[tot].to = u;
edge[tot].cap = rw;
edge[tot].flow = 0;
edge[tot].next = head[v];
head[v]=tot++;
}
void bfs(int st,int ed)
{
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
gap[0]=1;
int front = 0,rear=0;
dep[ed]=0;
q[rear++]=ed;
while(front!=rear)
{
int u = q[front++];
for(int i = head[u];i!=-1;i=edge[i].next)
{
int v = edge[i].to;
if(dep[v]!=-1)
continue;
q[rear++]=v;
dep[v]=dep[u]+1;
gap[dep[v]]++;
}
}
}
int s[maxn];
double sap(int st,int ed,int N)
{
bfs(st,ed);
memcpy(cur,head,sizeof(head));
int top = 0;
int u = st;
double ans = 0;
while(dep[st] < N)
{
if (u==ed)
{
double Min = INF;
int inser;
for(int i = 0;i<top;i++)
if(Min > edge[s[i]].cap-edge[s[i]].flow)
{
Min = edge[s[i]].cap - edge[s[i]].flow;
inser = i;
}
for(int i = 0;i<top;i++)
{
edge[s[i]].flow+=Min;
edge[s[i]^1].flow-=Min;
}
ans+=Min;
top = inser;
u = edge[s[top]^1].to;
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]=i;
break;
}
}
if(flag)
{
s[top++]=cur[u];
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!=st)
u = edge[s[--top]^1].to;
}
return ans;
}
struct Node
{
int u,v;
}v[maxn];
int n,m;
int a[maxn];
bool check(double mid)
{
init();
int s= 0,t=n+m+1;
for(int i = 1;i<=m;i++)
addedge(s,i,1);
for(int i = 1;i<=n;i++)
addedge(i+m,t,mid);
for(int i = 1;i<=m;i++)
{
addedge(i,v[i].u+m,INF);
addedge(i,v[i].v+m,INF);
}
double ans = sap(s,t,t+1);
return 1.0*m-ans<eps;
}
int d[maxn];
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
printf("Case #%d: ",cas++);
m = 1;
memset(d,0,sizeof(d));
scanf("%d",&n);
for (int i = 1;i<=n;i++)
scanf("%d",&a[i]);
for (int i = 1;i<=n;i++)
for (int j = i+1;j<=n;j++)
{
if(a[i]>a[j])
{
v[m].u = i;
v[m].v = j;
d[v[m].u]++;
d[v[m].v]++;
m++;
}
}
m--;
double l = 0;
double r = m;
for(int cnt = 1;cnt<=50;cnt++)
{
double mid = (l+r)/2;
if (check(mid))
r = mid;
else
l = mid;
}
printf("%.12lf\n",l);
}
}