• 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 }
  • 相关阅读:
    Selenium+Java自动化之如何优雅绕过验证码
    Java替换中使用正则表达式实现中间模糊匹配
    【转】Jmeter中使用CSV Data Set Config参数化不重复数据执行N遍
    【转】安全测试===如何查看浏览器保存的密码
    JMeter 中_time 函数的使用(时间戳、当前时间)
    TCP拆包粘包之分隔符解码器
    TCP粘包/拆包问题
    Netty 入门示例
    JDK AIO编程
    JDK NIO编程
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10651218.html
Copyright © 2020-2023  润新知