Nowcoder 第十四届华中科技大学程序设计竞赛决赛同步赛 K.Maximum average Sequence

裸最大密度子图:参考博客: 点击打开链接,论文:胡伯涛,最小割模型在信息学竞赛中的应用
/**
给定一个无向图,要求它的一个子图,使得子图中边数|E|与点数|V|的比值最大。

解法一:

假设答案为k ,则要求解的问题是:选出一个合适的点集V和边集E,令(|E| - k * |V|) 取得最大值。所谓“合适”是指满足如下限制:若选择某条边,则必选择其两端点。

建图:以原图的边作为左侧顶点,权值为1;原图的点作为右侧顶点,权值为-k(相当于 支出k)。

若原图中存在边(u,v),则新图中添加两条边([uv]-->u), ([uv]-->v),转换为最大权闭合子图。

解法二:

把原图中的无向边转换成两条有向边,容量为1。

设一源点,连接所有点,容量为U(取m)。

设一汇点,所有点连接汇点,容量为 U+2g-dv 。

二分枚举最大密度g,其中dv为v的度。

判断(U*n-MaxFlow)/2.>=0。

最后跳出的L就是最大密度。

拿这个L再重新建图,求最大流。

然后从s出发bfs或者dfs,走残留容量大于0的边,所有能到达的点就是答案。

具体分析过程见胡伯涛的论文《最小割模型在信息学竞赛中的应用》
**/
/**
nowcode 第十四届华中科技大学程序设计竞赛决赛同步赛 K
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int inf = 1e9;
const int maxn = 4000;
const double eps = 1e-8;
typedef long long ll;

struct Edge
{
    int fr,to;
    double cap,flow;
};

struct Dinic
{
    int n,m,s,t;
    vector<Edge>edges;
    vector<int>G[maxn+5];
    bool vis[maxn+5];
    int d[maxn+5];
    int cur[maxn+5];

    void Init(int n)
    {
        this->n = n;
        for(int i=0; i<=n; i++) G[i].clear();
        edges.clear();
    }

    void Addedge(int fr,int to,double cap)
    {
        edges.push_back((Edge)
        {
            fr,to,cap,0
        });
        edges.push_back((Edge)
        {
            to,fr,0,0
        });
        m = edges.size();
        G[fr].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BFS()
    {
        memset(vis,0,sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s] = 0, vis[s] = 1;
        while(!Q.empty())
        {
            int x = Q.front();
            Q.pop();
            for(int i=0,l=G[x].size(); i<l; i++)
            {
                Edge &e = edges[G[x][i]];
                if(!vis[e.to]&&e.cap>e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    double DFS(int x,double a)
    {
        if(x==t||a==0) return a;
        double flow = 0,f;
        for(int &i=cur[x],l=G[x].size(); i<l ; i++)
        {
            Edge &e = edges[G[x][i]];
            if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
            {
                e.flow+=f;
                edges[G[x][i]^1].flow -=f;
                flow+=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }

    double Maxflow(int s,int t)
    {
        this->s = s, this->t = t;
        double flow = 0;
        while(BFS())
        {
            memset(cur,0,sizeof(cur));
            flow+=DFS(s,(double)inf);
        }
        //cout<<flow<<endl;
        return flow;
    }

}my;
int n,a[105],x[10005],y[10005],tot,dv[105];
bool check2(double k)
{
     my.Init(n+2);
     for(int i=1;i<=tot;i++)
     {
         my.Addedge(x[i],y[i],1);
         my.Addedge(y[i],x[i],1);
     }
     for(int i=1;i<=n;i++)
     {
         my.Addedge(0,i,tot);
         my.Addedge(i,n+1,tot+2*k-dv[i]);
     }
     return ((tot*n - my.Maxflow(0,n+1))/2 >= eps );
}
int main()
{
    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]==0||a[j]%a[i]==0) x[++tot] = i, y[tot] = j, dv[i]++,dv[j]++;
    }
    double l = 0,r = n, mid;
    for(int i=1;i<=30;i++)
    {
        mid = (l+r)/2;
        if(check2(mid)) l = mid;
        else r = mid;
    }
    printf("%.10f\n",l);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_32944513/article/details/80215661