zoukankan      html  css  js  c++  java
  • Codeforces Round #170 (Div. 1) E. Binary Tree on Plane(最小费用流)

     

    题目大意

     

    给你平面上 n(2<=n<=400) 个点,要求用这些点组成一个二叉树(每个节点的儿子节点不超过两个),定义每条边的权值为两个点之间的欧几里得距离。求一个权值和最小的二叉树,并输出这个权值

    点 i 可以成为点 j 的的父亲的条件是:点 i 的 y 坐标比 j 的 y 坐标大!

    如果不存在这样的二叉树,输出 -1

     

    做法分析

     

    转换成为最小费用流

            1、把每个点 u 拆成两个点 u' 和 u''

            2、增加源点 source 和汇点 sink

            3、链接 source 和每个点 u',即 <source, u'> 容量为 2,费用为 0

            4、链接每个点 u'' 和 sink,即 <u'', sink> 容量为 1,费用为 0

            5、对于每两个点 u 和 v,如果 u 的纵坐标大于 v 的纵坐标,建边 <u', v''> 容量为 1,费用为 u 和 v 的欧几里得距离

    对建好的网络跑一遍最小费用最大流,如果流量 maxFlow!=n-1 那么无解,否则 minCost 就是一个最优解

     

    参考代码

    Binary Tree on Plane
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 #include <algorithm>
      6 #include <queue>
      7 
      8 #define INT_INF 0x3fffffff
      9 #define N 900
     10 #define E 1000000
     11 
     12 using namespace std;
     13 
     14 struct Edge
     15 {
     16     int st, en, cap, flow, next;
     17     double cost;
     18     Edge() {}
     19     Edge(int a, int b, int c, double d, int e)
     20     {
     21         st=a, en=b, cap=c, cost=d, next=e, flow=0;
     22     }
     23 } edge[E];
     24 int head[N], tot, now[N], pre[N];
     25 int source, sink, FLOW, n;
     26 double dis[N];
     27 queue<int> q;
     28 bool vs[N];
     29 
     30 struct data
     31 {
     32     double x, y;
     33     bool operator <(const data &a) const
     34     {
     35         if(y==a.y) return x<a.x;
     36         else return y>a.y;
     37     }
     38 } vertex[N];
     39 
     40 void add_edge(int st,int en,int cap,double cost)
     41 {
     42     edge[tot]=Edge(st, en, cap, cost, head[st]);
     43     head[st]=tot++;
     44 
     45     edge[tot]=Edge(en, st, 0, -cost, head[en]);
     46     head[en]=tot++;
     47 }
     48 
     49 bool SPFA()
     50 {
     51     for(int i=source; i<=sink; i++)
     52         dis[i]=INT_INF, vs[i]=false, now[i]=-1;
     53 
     54     while(!q.empty()) q.pop();
     55     q.push(source), dis[source]=0, vs[source]=true;
     56     while(!q.empty())
     57     {
     58         int u=q.front();
     59         q.pop(), vs[u]=0;
     60         for(int i=head[u], v; i!=-1; i=edge[i].next)
     61             if(edge[i].cap-edge[i].flow>0 && dis[v=edge[i].en]>dis[u]+edge[i].cost)
     62             {
     63                 dis[v]=dis[u]+edge[i].cost, now[v]=i;
     64                 if(!vs[v]) vs[v]=1, q.push(v);
     65             }
     66     }
     67     if(dis[sink]!=INT_INF) return true;
     68     else return false;
     69 }
     70 
     71 double MCMF()
     72 {
     73     double cost=0;
     74     FLOW=0;
     75     while(SPFA())
     76     {
     77         int flow=INT_INF;
     78         for(int u=sink; u!=source; u=edge[now[u]].st)
     79             if(flow>edge[now[u]].cap-edge[now[u]].flow)
     80                 flow=edge[now[u]].cap-edge[now[u]].flow;
     81         for(int u=sink; u!=source; u=edge[now[u]].st)
     82         {
     83             edge[now[u]].flow+=flow;
     84             edge[now[u]^1].flow-=flow;
     85         }
     86         cost+=flow*dis[sink];
     87         FLOW+=flow;
     88     }
     89     return cost;
     90 }
     91 
     92 double cal_dis(int a, int b)
     93 {
     94     return sqrt((vertex[a].x-vertex[b].x)*(vertex[a].x-vertex[b].x)+(vertex[a].y-vertex[b].y)*(vertex[a].y-vertex[b].y));
     95 }
     96 
     97 void build(int n)
     98 {
     99     tot=0, source=0, sink=n+n+1;
    100     for(int i=source; i<=sink; i++) head[i]=-1;
    101     for(int i=1; i<=n; i++) add_edge(source, i, 2, 0), add_edge(i+n, sink, 1, 0);
    102     for(int i=1; i<=n; i++)
    103         for(int j=i+1; j<=n; j++)
    104         {
    105             if(vertex[i].y==vertex[j].y) continue;
    106             add_edge(i, j+n, 1, cal_dis(i, j));
    107         }
    108 }
    109 
    110 int main()
    111 {
    112     scanf("%d", &n);
    113     for(int i=1; i<=n; i++) scanf("%lf%lf", &vertex[i].x, &vertex[i].y);
    114     sort(vertex+1, vertex+n+1);
    115 
    116     build(n);
    117     double ans=MCMF();
    118 
    119     if(FLOW!=n-1) printf("-1\n");
    120     else printf("%lf\n",ans);
    121     return 0;
    122 }

    AC通道

    Codeforces Round #170 (Div. 1) E. Binary Tree on Plane

  • 相关阅读:
    iptables命令参数简介
    在linux下开启IP转发的方法
    Linux配置IP路由
    NAT转换
    JS实验案例
    Ubuntu kylin优麒麟root用户与静态网络设置
    非对称加密-RSA
    对称加密-DES
    DM5详解
    Visio的安装教程
  • 原文地址:https://www.cnblogs.com/zhj5chengfeng/p/2950893.html
Copyright © 2011-2022 走看看