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

Posted xiuwenL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017 计蒜之道 初赛 第三场 D. 腾讯狼人杀 (点边都带权的最大密度子图)相关的知识,希望对你有一定的参考价值。

点边都带权的最大密度子图,且会有必须选的点.
写到一半没保存实验室断电,气炸.明天补详细题解.

#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\n",(L+R)*0.5);
    return 0;
}

以上是关于2017 计蒜之道 初赛 第三场 D. 腾讯狼人杀 (点边都带权的最大密度子图)的主要内容,如果未能解决你的问题,请参考以下文章

2018 计蒜之道 初赛 第三场

2018 计蒜之道 初赛 第三场

2017 计蒜之道 初赛 第五场 D. UCloud 的安全秘钥(困难)

2017 计蒜之道 初赛 第一场 B.阿里天池的新任务

2017计蒜之道 初赛 第二场 百度的科学计算器(简单)

腾讯课堂的物理实验(2017计蒜客初赛第三场)