zoukankan      html  css  js  c++  java
  • 【bzoj 2163】复杂的大门(算法效率--拆点+贪心)

    题目:你去找某bm玩,到了门口才发现要打开他家的大门不是一件容易的事……
    他家的大门外有n个站台,用1到n的正整数编号。你需要对每个站台访问一定次数以后大门才能开启。站台之间有m个单向的传送门,通过传送门到达另一个站台不需要花费任何代价。而如果不通过传送门,你就需要乘坐公共汽车,并花费1单位的钱。值得庆幸的是,任意两个站台之间都有公共汽车直达。
    现在给你每个站台必须访问的次数Fi,对于站台i,你必须恰好访问Fi次(不能超过)。
    我们用u、v、w三个参数描述一个传送门,表示从站台u到站台v有一个最多可以使用w次的传送门(不一定要使用w次)。值得注意的是,对于任意一对传送门(u1,v1)和(u2,v2),如果有u1<u2,则有v1≤v2;如果有v1<v2,则有u1≤u2;且u1=u2和v1=v2不同时成立。
    你可以从任意的站台开始,从任意的站台结束。出发去开始的站台需要花费1单位的钱。你需要求出打开大门最少需要花费多少单位的钱。

    解法:由于要最小花费,那免费的传送门肯定尽量多用。而又要求每个站台必须不多不少访问 Fi 次,我们可以把每个站台拆成分成 “入度和出度”计算,也就是“到达和出发的次数”。
           接着就是贪心的思想。由题意可知,不存在 [l,r] 和 [ll,rr] 既满足 l<ll,又满足 r>rr,而且没有 l,r 都相同的传送梦。那么,我们把传送门按先起始点,再终结点从小到大的顺序排序之后,直接从前到后扫传送门,贪心每种用到极致 (•́⌄•́๑)૭✧,也就是在起始点和终结点都<= Fi 的情况下用到最多。这样可以的原因是:对于当前传送门 [l,r] 和下一个传送门 [ll,rr],若没有相等的,那么对于当前的 l 和 r 都是能减少花费就减少,因为没有其他的传送门能到达它们了。若是 l=ll,那么对于 r 就是尽量能减少花费就减少;而若是 r=rr,那就是对于 l 这样了。因此可以这样贪心。

          P.S.而我下面屏蔽的代码就是没有理解“拆点”的意义。(⊙_⊙;)… 一定要拆“入和出”,否则会漏算或多算的。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<iostream>
     6 using namespace std;
     7 #define N 10010
     8 #define M 100010
     9 #define W 50010
    10 
    11 int n,m;
    12 int gin[N],gout[N];
    13 struct node{int x,y,w;}a[M];
    14 
    15 bool cmp(node x,node y)
    16 {
    17     if (x.x!=y.x) return x.x<y.x;
    18     return x.y<y.y;
    19 }
    20 int mmin(int x,int y) {return x<y?x:y;}
    21 int main()
    22 {
    23     int i,j,ans=0;
    24     scanf("%d%d",&n,&m);
    25     for (i=1;i<=n;i++)
    26     {
    27       scanf("%d",&gin[i]);
    28       gout[i]=gin[i];
    29       ans+=gin[i];
    30     }
    31     for (i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
    32     sort(a+1,a+1+m,cmp);
    33     j=1;
    34     for (i=1;i<=n;i++)
    35     {
    36       while (j<=m && a[j].x==i)
    37       {
    38         int x=i,y=a[j].y;
    39         int tmp=mmin(mmin(gout[x],gin[y]),a[i].w);
    40         gout[x]-=tmp,gin[y]-=tmp;//直到现在能入y和出x的次数
    41         ans-=tmp, j++;
    42       }
    43     }
    44     /*for (i=1;i<=m;i++)
    45     {
    46       int x=a[i].x,y=a[i].y;
    47       int tmp=mmin(mmin(gout[x],gin[y]),a[i].w);
    48       gout[x]-=tmp,gin[y]-=tmp;
    49       ans-=tmp;
    50     }*/
    51     /*j=1;
    52     for (i=1;i<=n;i++)
    53     {
    54       while (j<=m && a[j].x==i)
    55       {
    56         int x=i,y=a[j].y;
    57         //int tmp=mmin(mmin(h[x],h[y]),a[j].w);
    58         //h[x]-=tmp,h[y]-=tmp;//同一个点重复计算了
    59         ans-=tmp, j++;
    60       }
    61     }*/
    62     /*  int cnt=0,p=1;//x min & y min
    63       for (i=2;i<=m;i++)
    64           if (a[i].x!=a[i-1].x) a[++p]=a[i];//推广!因为h[i]>1,所以不删次优的边
    65       p=1;
    66       for (i=2;i<=m;i++)
    67         if (a[i].y!=a[i-1].y) a[++p]=a[i];*/
    68     printf("%d
    ",ans);
    69     return 0;
    70 }
  • 相关阅读:
    php多态
    ssl certificate problem: self signed certificate in certificate chain
    test plugin
    open specific port on ubuntu
    junit vs testng
    jersey rest service
    toast master
    use curl to test java webservice
    update folder access
    elk
  • 原文地址:https://www.cnblogs.com/konjak/p/6071136.html
Copyright © 2011-2022 走看看