• 2017 计蒜之道 初赛 第三场 D. 腾讯狼人杀 (点边都带权的最大密度子图)


    点边都带权的最大密度子图,且会有必须选的点.
    (frac{sum w_e}{k*(2n-k)})的最大值,其中k为子图点数
    设$$h(g) = sum w_e - g*(2nk-k^2)$$
    假设最优解为(g*),则当(g<g*)时,(h(g)>0);(g>g*时,h(g)<0),以此判断条件二分搜索.
    但是((2nk-k^2))不能直接转化为点权,需要做点改变.

    [sum w_e - g*2nk+g*k^2 = sum w_e + frac{k(k-1)}{2}*2g+kg-2kng ]

    [= sum (w_e + 2g) - (2ng-g)*k ]

    这个式子的意义等于对原图的每一条边都加上了边权2g,若原图两点间没有边,则新建一条权值为2g的边. 每个点的点权为((2ng-g))
    这样就转化成了点边均带权的最大密度子图模型.
    还有一些必须要选的点.因为在最大权闭合子图的模型中,若源点S与点i之间的边不是割,则表示没有选择这个点.根据这个性质,我们在建图的时候对必须选的点,只从源点S向它建边,容量为正无穷,保证它不会成为割中的边.然后在总的流量中加上这个点的点权.
    第二十组数据特别卡精度,但是eps设得过高会T.

    #include<bits/stdc++.h>
    using namespace std;
    const double eps = 1e-7;
    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] += 2*g + G[i][j];
                F.AddEdge(i,j,G[i][j] + 2*g);
            }
        }
    
        for(int i=1;i<=N;++i){
            if(tag[i]){
                flow += U + 2*g*(2*N-1) - d[i];
                F.AddEdge(s, i, INF);
            }
            else{
                F.AddEdge(s,i,U);
                F.AddEdge(i,t, U + 2 * g * (2*N - 1) - d[i]);
            }
        }
    
        double hg = (U*N - flow - F.maxFlow_sap(s,t,t+1)) * 0.5;
        return hg > eps;
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt", "r", stdin);
            freopen("out.txt", "w", stdout);
        #endif
        int u,v,w;
        scanf("%d %d",&N, &M);
        for(int i=1;i<=M;++i){
            scanf("%d %d %d",&u, &v, &w);
            G[u][v] = G[v][u] = w;
        }
        for(int i=1;i<=N;++i){
            scanf("%d",&tag[i]);
        }
        double L = 0, R = 200, mid;
        while(R - L >= eps){
            mid = (L+R) * 0.5;
            if(check(mid)) L = mid;
            else R = mid;
        }
        printf("%.6f
    ",(L+R)*0.5);
        return 0;
    }
    
    
  • 相关阅读:
    二叉树的遍历
    Balanced Binary Tree(平衡二叉树)
    Maximum Depth of Binary Tree(二叉树最大深度)
    Binary Tree Level Order Traversal(二叉树广度优先遍历或逐层遍历)
    解决mac下sublime中文乱码
    ubuntu下vi文本后出现不正常的情况
    Linux top命令的用法详细详解
    在Ubuntu 12.04下搭建Cocos2d-x 3.0 生成LuaBindings环境
    iOS7(Xcode5)中隐藏状态栏的方法
    VS2015 打包添加系统必备组件
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9748771.html
Copyright © 2020-2023  润新知