zoukankan      html  css  js  c++  java
  • CF51F Caterpillar (边双+树形DP)

    题目传送门

    题目大意:给你一张n个点m条边的图。每次操作可以把两个点合并成一个(与之相连的边也都要连到新点上)。求把图中每个联通块都变成“毛毛虫”的最小操作次数。“毛毛虫”必须是一棵树(可以存在自环),且其中必须存在一条主链,使得主链外的点到主链上的任意一点距离为1。$nleq 2000,mleq 10^{5}$

    树上乱搞题目×1

    首先把原图用边双$tarjan$缩成一棵树

    然后我们想办法找出这条主链,似乎也只能$DP$了

    定义$f(x,0/1)$表示 主链一端在$x$子树内另一端在$x$点/主链两个端点都在$x$子树内 付出的最小代价

    对于不在主链上的点,需要把整颗子树合并成一个点,画一画图发现这个数量就是这个子树内的叶节点数量!

    $f(x,0)=min{f(v,0)+合并其他子树的花费}$

    $f(x,1)=min(f(v_{0},0)+f(v_{1},0)+合并其他子树的花费)$

    合并其他子树的花费很好推,但式子太长就不放了

    这也意味着我们$DP$时需要挑一个非叶节点为根进行$DP$

    题目并没有保证所有点都在一个联通块内..每个联通块都要统计一遍,好麻烦..

    时间可以被菊花图卡成$O(n^{2})$,但仍能轻松通过全部数据

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #define N1 2010
      5 #define M1 100050
      6 using namespace std;
      7 const int inf=0x3f3f3f3f;
      8 
      9 template <typename _T> void read(_T &ret)
     10 {
     11     ret=0; _T fh=1; char c=getchar();
     12     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     13     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     14     ret=ret*fh;
     15 }
     16 
     17 struct Edge{
     18 int to[M1*2],nxt[M1*2],val[M1*2],head[N1],cte;
     19 void ae(int u,int v,int w)
     20 { cte++; to[cte]=v; nxt[cte]=head[u]; val[cte]=w; head[u]=cte; }
     21 }e,g;
     22 
     23 int n,m,num;
     24 int dfn[N1],low[N1],use[N1],stk[N1],dad[N1],tp,tim,que[N1],tl;
     25 int f[N1][2],sum[N1],sz[N1],inc[N1],vis[N1];
     26 void init()
     27 {
     28     memset(f,0,(num+1)*8);   memset(sz,0,(num+1)*4);  memset(sum,0,(num+1)*4); 
     29     memset(vis,0,(num+1)*4); memset(inc,0,(num+1)*4); memset(g.head,0,(num+1)*4); 
     30     tl=tp=tim=num=0; g.cte=0;
     31 }
     32 
     33 void tarjan(int x,int fa)
     34 {
     35     int j,v; que[++tl]=x;
     36     dfn[x]=low[x]=++tim; use[x]=1; stk[++tp]=x;
     37     for(j=e.head[x];j;j=e.nxt[j])
     38     {
     39         if(e.val[j]==fa) continue;
     40         v=e.to[j];
     41         if(!dfn[v]){
     42             tarjan(v,e.val[j]);
     43             low[x]=min(low[x],low[v]);
     44         }else if(use[v]){
     45             low[x]=min(low[x],dfn[v]);
     46         }
     47     }
     48     if(low[x]==dfn[x])
     49     {
     50         num++;
     51         while(stk[tp]!=x)
     52             use[stk[tp]]=0, dad[stk[tp]]=num, tp--;
     53         use[stk[tp]]=0, dad[stk[tp]]=num, tp--;
     54     }
     55 }
     56 
     57 void dfs(int x,int fa)
     58 {
     59     int j,v; sz[x]=1; vis[x]=1;
     60     for(j=g.head[x];j;j=g.nxt[j])
     61     {
     62         v=g.to[j]; if(v==fa) continue;
     63         dfs(v,x); 
     64         sz[x]+=sz[v]; sum[x]+=sum[v];
     65     }
     66     int k,v0,v1; 
     67     if(inc[x]>1) f[x][0]=f[x][1]=inf; else sum[x]=1;
     68     for(j=g.head[x];j;j=g.nxt[j])
     69     {
     70         v0=g.to[j]; if(v0==fa) continue; 
     71         f[x][0]=min(f[x][0],f[v0][0]+(sz[x]-1-sz[v0])-(sum[x]-sum[v0])); 
     72         for(k=g.nxt[j];k;k=g.nxt[k])
     73         {
     74             v1=g.to[k]; if(v1==fa) continue; 
     75             f[x][1]=min(f[x][1],f[v0][0]+f[v1][0]+(sz[x]-sz[v0]-sz[v1]-1)-(sum[x]-sum[v0]-sum[v1])); 
     76         }
     77     }
     78 }
     79 int de;
     80 
     81 int solve(int x)
     82 {
     83     int i,j,ans=0,root; init(); 
     84     tarjan(x,0);
     85     if(num<=2){ return tl-num; }
     86     for(i=1;i<=tl;i++) 
     87     {
     88         x=que[i];
     89         for(j=e.head[x];j;j=e.nxt[j]) if(dad[x]!=dad[e.to[j]]) 
     90             g.ae(dad[x],dad[e.to[j]],0), inc[dad[e.to[j]]]++;
     91     }
     92     for(i=1;i<=num;i++) if(inc[i]>1){ root=i; dfs(root,0); break; }
     93     for(i=1,ans=inf;i<=num;i++) if(inc[i]>1)
     94         if(i!=root) ans=min(ans,f[i][1]+(num-sz[i])-(sum[root]-sum[i]));
     95         else ans=min(ans,f[i][1]);
     96     return ans+tl-num;
     97 }
     98 
     99 int main()
    100 {
    101     int i,j,x,y,ans=-1;
    102     scanf("%d%d",&n,&m);
    103     for(i=1;i<=m;i++) read(x), read(y), e.ae(x,y,i), e.ae(y,x,i);
    104     for(i=1;i<=n;i++) if(!dfn[i]) ans+=solve(i)+1;
    105     printf("%d
    ",ans);
    106     return 0;
    107 }
  • 相关阅读:
    CodeForces 706C Hard problem
    CodeForces 706A Beru-taxi
    CodeForces 706B Interesting drink
    CodeForces 706E Working routine
    CodeForces 706D Vasiliy's Multiset
    CodeForces 703B Mishka and trip
    CodeForces 703C Chris and Road
    POJ 1835 宇航员
    HDU 4907 Task schedule
    HDU 4911 Inversion
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10651218.html
Copyright © 2011-2022 走看看