zoukankan      html  css  js  c++  java
  • luogu3651 展翅翱翔之时 (はばたきのとき)[基环树+贪心]

    考前随便做点水题愉♂悦身心 有助于退役

    这题意思其实就是说要把外向基环树森林改成一个环的最小代价。

    依照套路,先对每棵基环树的树做dp,这里因为要是环,要把所有的树都拆成链,然后连接。所以考虑以最小代价拆掉每一个树。

    因为对于树的每层,只能选择出一个儿子作为链的部分保留下来,所以贪心的尽量选权值大的儿子留下来,其他的全部作为另一条链的开头准备接到环上。

    所以树的部分就是一个简单的树形DP。

    然后看环上的DP,相当于是要把我们之前搞出来的所有的链全部接上去,所以环上至少要有一个边断开,让这些链接上去。

    所以环上,每条边要么把入点连着的链断开,接入环中某处,要么直接断掉这条边将一些链给接上去。

    这时只要对环上每条边以这两种方案择优选取,最后发现最优方案如果没有环上边被断开,就强制找一个最小的代价让环上边断掉。

    当图是一个基环树森林的时候,不影响正确性,我们需要让每棵树的环都断开一个,以互相接入成为环,所以每个基环树可以独立做。

    不过注意一个特例:整个图就是一个环,这时就不需要断了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=1e5+7,INF=0x3f3f3f3f;
    24 struct thxorz{
    25     int head[N],nxt[N<<1],to[N<<1],tot;
    26     thxorz(){tot=1;}
    27     inline void add(int x,int y){
    28         to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
    29         to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
    30     }
    31 }G;
    32 ll ans;
    33 int n;
    34 #define y G.to[j]
    35 int vis[N],lp[N],val[N],chain[N],m,lpfa,flag,rt;
    36 void dfs(int x){//dbg(x);
    37     vis[x]=1;
    38     for(register int j=G.head[x];j&&!flag;j=G.nxt[j])if(j&1){//mistake:the direction of the edge!
    39         if(vis[y])return lpfa=y,flag=1,lp[m=1]=x,void();
    40         else{dfs(y);if(flag)lp[++m]=x;}
    41     }
    42     if(!flag)vis[x]=0;
    43     if(x==lpfa)flag=0;
    44 }
    45 void dp(int x){//dbg(x);
    46     vis[x]=1;ll sum=0;
    47     for(register int j=G.head[x];j;j=G.nxt[j])if(!vis[y])dp(y),sum+=val[y],MAX(chain[x],val[y]);
    48     ans+=sum-chain[x];
    49 }
    50 #undef y
    51 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    52     read(n);
    53     for(register int i=1,x;i<=n;++i)read(x),read(val[i]),G.add(x,i);
    54     for(register int i=1;i<=n;++i)if(!vis[i]){//dbg(i);
    55         flag=0,dfs(i);int chosen=0;//dbg("ok");dbg(m);
    56         if(m==n)break;
    57         for(register int j=1;j<=m;++j)dp(lp[j]);//dbg(lp[j]);
    58         #define nxt (j+1>m?1:j+1)//attention to the order..
    59         for(register int j=1;j<=m;++j){
    60             if(chain[lp[j]]<val[lp[nxt]])ans+=chain[lp[j]];
    61             else ans+=val[lp[nxt]],chosen=1;
    62         }
    63         if(!chosen){//dbg2(i,chosen);
    64             int tmp=INF;
    65             for(register int j=1;j<=m;++j)MIN(tmp,-chain[lp[j]]+val[lp[nxt]]);
    66             ans+=tmp;
    67         }
    68     }
    69     printf("%lld
    ",ans);
    70     return 0;
    71 }
    View Code

    总结:这题也涉及一个断环的操作,不过是需要考察性质之后发现的,是一个不那么显然的题目。。。

  • 相关阅读:
    Mysql 查看 数据库/表 磁盘占用
    COLA 4.0 整洁面向对象分层架构
    《语言选择与就业方向》(2010/06/09)
    《为什么程序员不愿写文档》(2010/06/22)
    《我?还是我们?》(2010/06/30)
    《选择大公司还是小公司》(2010/06/11)
    《加班,加班,加班》(2010/06/17)
    《薪水的苦恼》(2010/06/15)
    《新手面试时的常见问题和对策》(2010/06/15)
    《大量编程带来的快乐和烦恼》(2010/06/20)
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11823073.html
Copyright © 2011-2022 走看看