zoukankan      html  css  js  c++  java
  • [BZOJ3206][APIO2013]道路费用(最小生成树)

    3206: [Apio2013]道路费用

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 568  Solved: 266
    [Submit][Status][Discuss]

    Description

     

    Input

    第一行包含三个由空格隔开的整数N,M和K。
    接下来的 M行描述最开始的M 条道路
    这M行中的第i行包含由空格隔开的整数ai,bi和c i,表示有一条在a i和b i之间,费用为c i的双向道路。
    接下来的K行描述新建的K条道路。
    这 K行中的第i行包含由空格隔开的整数 xi和yi,表示有一条连接城镇xi和yi新道路
    最后一行包含N个由空格隔开的整数,其中的第j个为pj,表示从城镇j 前往城镇 1的人数。
    输入也满足以下约束条件。
    1 ≤ N ≤ 100000;1 ≤ K ≤ 20;1 ≤ M ≤ 300000;对每个i和j,1 ≤ ci, pj ≤ 10^6;
    注意:边权值可能相同

    Output

    你的程序必须输出恰好一个整数到标准输出,表示能获得的最大的收入。

    Sample Input

    5 5 1
    3 5 2
    1 2 3
    2 3 5
    2 4 4
    4 3 6
    1 3
    10 20 30 40 50

    Sample Output

    400

    HINT


    在样例中, Mr. Greedy应该将新道路(1,3)的费用设置为 5分钱。

    在这个费用下,他可以选择道路(3,5),(1,2),(2,4)和(1,3)来最小化总费用,这个费用为14。

    从城镇 3出发的 30个人和从城镇 5出发的 50个人将经过新道路前往城镇 1,因此他可以获得为(30+50)_5=400 分钱的最好收入。

    如果我们这样做,将新道路(1,3)的费用设置为 10分钱。

    根据传统的限制,Mr. Greedy必须选择(3,5),(1,2),(2,4)和(2,3),因为这是唯一费用最小的集合

    。因此,在嘉年华的过程中道路(1,3)将没有任何收入。

    Source

    [Submit][Status][Discuss]

    这种题一般不是数据结构+分类讨论,就是缩图。

    1.首先把K条边全部选上,这个时候图可能仍然不连通,于是将M条原边排序,从小到大加入直到图连通。根据M条边权值互不相同可以知道,加进来的这些原边是任意一个方案都必须有的。我们将原边构成的连通块缩成点,显然图最多只有K+1个点。

    2.为了保证后面枚举的复杂度,我们要找到能将K+1个点连通起来的最小的K条边,可以发现后面枚举只会使用这K条原边。

    3.$O(2^K)$枚举K条边并加入图中(如果构成环则退出),剩下的将选出的K条原边从小到大加入,建出当前方案下的MST。

    4.现在需要确定每条Mr. Greedy的边的权值,根据MST的圈性质可知,边<u,v>的权值肯定不能大于MST上u到v的路径中原边的最大值,依次暴力确定即可。

    时间复杂度$O(malpha(m)+K^22^K)$,理论上可能并不能过。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=l; i<=r; i++)
     4 typedef long long ll;
     5 using namespace std;
     6 
     7 const int N=100010,M=300010,inf=1000000000;
     8 int n,m,K,tot,tmp,cnt,rt,x,d[N],to[110],nxt[110],c[35],f[N],h[N],fa[2][N];
     9 ll sz[N],val[N],ans;
    10 struct E{ int x,y,z; bool operator <(const E &a)const{ return z<a.z; }; }a[M],b[35];
    11 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    12 int get(int k,int x){ return (fa[k][x]==x) ? x : fa[k][x]=get(k,fa[k][x]); }
    13 void uni(int k,int x,int y){ int u=get(k,x),v=get(k,y); if (u!=v) fa[k][u]=v; }
    14 
    15 void dfs(int x){
    16     sz[x]=val[x];
    17     for (int i=h[x],k; i; i=nxt[i])
    18         if ((k=to[i])!=fa[1][x])
    19             fa[1][k]=x,d[k]=d[x]+1,dfs(k),sz[x]+=sz[k];
    20 }
    21 
    22 int main(){
    23     freopen("bzoj3206.in","r",stdin);
    24     freopen("bzoj3206.out","w",stdout);
    25     scanf("%d%d%d",&n,&m,&K);
    26     rep(i,1,m) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    27     sort(a+1,a+m+1);
    28     rep(i,1,n) fa[0][i]=fa[1][i]=i;
    29     rep(i,1,K) scanf("%d%d",&b[i].x,&b[i].y),uni(0,b[i].x,b[i].y);
    30     rep(i,1,m){
    31         int u=get(0,a[i].x),v=get(0,a[i].y);
    32         if (u!=v) fa[0][u]=v,uni(1,a[i].x,a[i].y);
    33     }
    34     rt=get(1,1);
    35     rep(i,1,n) if (get(1,i)==i) c[++tot]=i;
    36     rep(i,1,n) scanf("%d",&x),val[get(1,i)]+=x;
    37     rep(i,1,m) a[i].x=get(1,a[i].x),a[i].y=get(1,a[i].y);
    38     rep(i,1,K) b[i].x=get(1,b[i].x),b[i].y=get(1,b[i].y);
    39     rep(i,1,m){
    40         int u=get(1,a[i].x),v=get(1,a[i].y);
    41         if (u!=v) a[++tmp]=a[i],fa[1][u]=v;
    42     }
    43     for (int S=0; S<1<<K; S++){
    44         bool flag=0; cnt=0;
    45         rep(i,1,tot) fa[1][c[i]]=h[c[i]]=0,f[c[i]]=inf,fa[0][c[i]]=c[i];
    46         rep(i,1,K) if (S&(1<<(i-1))){
    47             int u=get(0,b[i].x),v=get(0,b[i].y);
    48             if (u==v) { flag=1; break; } fa[0][u]=v;
    49             add(b[i].x,b[i].y); add(b[i].y,b[i].x);
    50         }
    51         if (flag) continue;
    52         rep(i,1,K){
    53             int u=get(0,a[i].x),v=get(0,a[i].y);
    54             if (u!=v) fa[0][u]=v,add(a[i].x,a[i].y),add(a[i].y,a[i].x);
    55         }
    56         dfs(rt);
    57         rep(i,1,K){
    58             int u=a[i].x,v=a[i].y;
    59             if (d[u]<d[v]) swap(u,v);
    60             for (; d[u]!=d[v]; u=fa[1][u]) f[u]=min(f[u],a[i].z);
    61             for (; u!=v; u=fa[1][u],v=fa[1][v]) f[u]=min(f[u],a[i].z),f[v]=min(f[v],a[i].z);
    62         }
    63         ll tmp=0;
    64         rep(i,1,K) if (S&(1<<(i-1))){
    65             int u=b[i].x,v=b[i].y;
    66             if (d[u]<d[v]) swap(u,v);
    67             tmp+=sz[u]*f[u];
    68         }
    69         ans=max(ans,tmp);
    70     }
    71     printf("%lld
    ",ans);
    72     return 0;
    73 }
  • 相关阅读:
    日记搬迁
    学生会管理系统(JavaWeb与数据库课程小实践)
    疯狂忙碌边缘
    英语复习二:每单元的翻译篇章
    Don't always upset yourself !
    一文教你读懂并使用GTD高效时间管理法
    Day05-黑马学习篇(二)matplot基本绘图函数集合
    Day04-黑马学习篇(一)matplot画图基本要点
    Day03-基础篇(四)Pandas与数据清洗
    Day02 基础篇(三)用NumPy快速处理数据
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8920714.html
Copyright © 2011-2022 走看看