100548C The Problem Needs 3D Arrays (最大密度子圖)
阿新 • • 發佈:2018-12-21
題意:求一個子序列,使得這個子序列的 逆序數/長度 最大
解題思路:如果知道什麼是最大密度子圖,那麼這道題就是裸題了。這裡儲存一下模板~!
感謝大佬的模板
這個模板可以求 帶點權帶邊權某些點必須用的最大密度子圖
#include<bits/stdc++.h> using namespace std; const double eps = 1e-8; const int INF = 0x3f3f3f3f; const int MAXN= 405;//點數的最大值 const int MAXM= 1e6 + 10;//邊數的最大值 #define captype double struct Edge{ int from,to,next; captype cap; }; struct SAP_MaxFlow{ Edge edges[MAXM]; int tot,head[MAXN]; int gap[MAXN]; int dis[MAXN]; int cur[MAXN]; int pre[MAXN]; void init(){ tot=0; memset(head,-1,sizeof(head)); } void AddEdge(int u,int v,captype c,captype rc=0){ edges[tot] = (Edge){u,v,head[u],c}; head[u]=tot++; edges[tot] = (Edge){v,u,head[v],rc}; head[v]=tot++; } captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源點和匯點的總點個數,這個一定要注意 memset(gap,0,sizeof(gap)); memset(dis,0,sizeof(dis)); memcpy(cur,head,sizeof(head)); pre[sNode] = -1; gap[0]=n; captype ans=0; int u=sNode; while(dis[sNode]<n){ if(u==eNode){ captype Min=INF ; int inser; for(int i=pre[u]; i!=-1; i=pre[edges[i^1].to]) if(Min>edges[i].cap){ Min=edges[i].cap; inser=i; } for(int i=pre[u]; i!=-1; i=pre[edges[i^1].to]){ edges[i].cap-=Min; edges[i^1].cap+=Min; } ans+=Min; u=edges[inser^1].to; continue; } bool flag = false; int v; for(int i=cur[u]; i!=-1; i=edges[i].next){ v=edges[i].to; if(edges[i].cap>0 && dis[u]==dis[v]+1){ flag=true; cur[u]=pre[v]=i; break; } } if(flag){ u=v; continue; } int Mind= n; for(int i=head[u]; i!=-1; i=edges[i].next) if(edges[i].cap>0 && Mind>dis[edges[i].to]){ Mind=dis[edges[i].to]; cur[u]=i; } gap[dis[u]]--; if(gap[dis[u]]==0) return ans; dis[u]=Mind+1; gap[dis[u]]++; if(u!=sNode) u=edges[pre[u]^1].to; //退一條邊 } return ans; } }F; int N, M ; double d[MAXN]; int tag[MAXN]; int G[405][405]; #define U (400 * 2100) bool check(double g) { int s = 0, t = N+1; F.init(); double flow = 0; for(int i=1;i<=N;++i){ d[i] = 0.0; for(int j=1;j<=N;++j){ if(i==j) continue; d[i] += G[i][j];//如果公式計算出來,邊權跟g有關,就要加上相應的g F.AddEdge(i,j,G[i][j]);//如果公式計算出來,邊權跟g有關,就要加上相應的g } } for(int i=1;i<=N;++i){ if(tag[i]){ flow += U + 2*g - d[i];//有點權的話,這個2*g還要再乘那個點權 F.AddEdge(s, i, INF); } else{ F.AddEdge(s,i,U); F.AddEdge(i,t, U + 2 * g - d[i]);//有點權的話,這個2*g還要再乘那個點權 } } double hg = (U*N - flow - F.maxFlow_sap(s,t,t+1)) * 0.5; return hg > eps; } int A[MAXN]; int main() { int T; scanf("%d",&T); for(int qqq=1;qqq<=T;qqq++){ int u,v,w; memset(G,0,sizeof(G)); 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[j]<A[i]) G[i][j] = G[j][i] = 1;//如果有邊權,這裡改成其他即可 } for(int i=1;i<=N;++i){ tag[i]=0;//必須用的話設為1 } double L = 0, R = 200, mid; while(R - L >= eps){ mid = (L+R) * 0.5; if(check(mid)) L = mid; else R = mid; } printf("Case #%d: %.10f\n",qqq,(L+R)*0.5); } return 0; }