zoukankan      html  css  js  c++  java
  • [cf611H]New Year and Forgotten Tree

    首先,来构造这棵树的形态

    称位数相同的点为一类点,从每一类点中任选一个点,具有以下性质:

    1.每一类中选出的点的导出子图连通(是一颗树)

    2.每一条边必然有一个端点属于某一类中选出的点

    (关于“若有解,一定存在上述这种形式的解”的证明可能比较困难,大概感性理解一下?)

    由于类别很少(记为$m=lfloorlog_{10}n floor+1$),$o(m^{m-2})$或$o{frac{(m+1)m}{2}choose m-1}$暴力确定这$m$类点中选出的点的树形态(实际差不了多少),接下来每一条边相当于可以使边端点中的一类未在连通块中加入连通块,即如果记$s_{x}$表示$x$类点剩余的点数量,之后每一条边相当于选择$s_{x}$或$s_{y}$减小1

    很明显是一个网络流的模型,判一下是否满流即可,复杂度大概可过

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 200005
      4 #define M 7
      5 #define oo 0x3f3f3f3f
      6 #define fi first
      7 #define se second
      8 struct ji{
      9     int nex,to,len;
     10 }edge[M*M*M];
     11 queue<int>q;
     12 vector<pair<int,int> >ansE;
     13 int V,E,n,m,head[M*M],len[N],a[M][M],id[M][M],tot[M],pos[M],now[M],f[M],d[M*M],work[M*M];
     14 char s1[M],s2[M];
     15 int find(int k){
     16     if (k==f[k])return k;
     17     return find(f[k]);
     18 }
     19 void add(int x,int y,int z){
     20     edge[E].nex=head[x];
     21     edge[E].to=y;
     22     edge[E].len=z;
     23     head[x]=E++;
     24     if (E&1)add(y,x,0);
     25 }
     26 bool bfs(){
     27     memset(d,oo,sizeof(d));
     28     d[0]=0;
     29     q.push(0);
     30     while (!q.empty()){
     31         int k=q.front();
     32         q.pop();
     33         for(int i=head[k];i!=-1;i=edge[i].nex)
     34             if ((edge[i].len)&&(d[edge[i].to]==oo)){
     35                 d[edge[i].to]=d[k]+1;
     36                 q.push(edge[i].to);
     37             }
     38     }
     39     return d[V+m+1]<oo;
     40 }
     41 int dfs(int k,int s){
     42     if (k>V+m)return s;
     43     for(int &i=work[k];i!=-1;i=edge[i].nex)
     44         if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){
     45             int p=dfs(edge[i].to,min(s,edge[i].len));
     46             if (p){
     47                 edge[i].len-=p;
     48                 edge[i^1].len+=p;
     49                 return p;
     50             }
     51         }
     52     return 0;
     53 }
     54 int dinic(){
     55     int k,ans=0;
     56     while (bfs()){
     57         memcpy(work,head,sizeof(work));
     58         while (k=dfs(0,oo))ans+=k;
     59     }
     60     return ans;
     61 }
     62 bool dfs(int k,int x,int y){
     63     if (k>=m){
     64         E=0;
     65         memset(head,-1,sizeof(head));
     66         for(int i=1;i<=m;i++)
     67             for(int j=i;j<=m;j++){
     68                 add(0,id[i][j],a[i][j]);
     69                 add(id[i][j],V+i,oo);
     70                 add(id[i][j],V+j,oo);
     71             }
     72         for(int i=1;i<=m;i++)add(V+i,V+m+1,tot[i]);
     73         if (dinic()==n-m){
     74             for(int i=1;i<=m;i++)
     75                 for(int j=i;j<=m;j++)
     76                     for(int k=head[id[i][j]];k!=-1;k=edge[k].nex)
     77                         if (edge[k].to>V){
     78                             int p=edge[k].to-V;
     79                             for(int l=edge[k].len;l<oo;l++)ansE.push_back(make_pair(++now[p],pos[i+j-p]));
     80                         }
     81             return 1;
     82         }
     83         return 0;
     84     }
     85     for(int i=x;i<=m;i++)
     86         for(int j=y;j<=m;j++)
     87             if ((a[i][j])&&(find(i)!=find(j))){
     88                 int ii=find(i);
     89                 f[ii]=j;
     90                 a[i][j]--;
     91                 ansE.push_back(make_pair(pos[i],pos[j]));
     92                 if (dfs(k+1,i,j))return 1;
     93                 f[ii]=ii;
     94                 a[i][j]++;
     95                 ansE.pop_back();
     96             }
     97     return 0;
     98 }
     99 int main(){
    100     scanf("%d",&n);
    101     for(int i=1;i<n;i++){
    102         scanf("%s%s",s1,s2);
    103         int x=strlen(s1),y=strlen(s2);
    104         if (x>y)swap(x,y);
    105         a[x][y]++;
    106     }
    107     for(int i=1;i<=n;i++){
    108         len[i]=len[i/10]+1;
    109         tot[len[i]]++;
    110     }
    111     m=len[n];
    112     for(int i=1;i<=m;i++)tot[i]--;
    113     pos[1]=1;
    114     for(int i=2;i<=m;i++)pos[i]=pos[i-1]*10;
    115     memcpy(now,pos,sizeof(now));
    116     for(int i=1;i<=m;i++)f[i]=i;
    117     for(int i=1;i<=m;i++)
    118         for(int j=i;j<=m;j++)id[i][j]=++V;
    119     if (!dfs(1,1,1))printf("-1");
    120     else{
    121         for(int i=0;i<ansE.size();i++)printf("%d %d
    ",ansE[i].fi,ansE[i].se);
    122     }
    123 } 
    View Code
  • 相关阅读:
    14_java之变量|参数|返回值|修饰符
    NYOJ 202 红黑树 (二叉树)
    NYOJ 138 找球号(二) (哈希)
    NYOJ 136 等式 (哈希)
    NYOJ 133 子序列 (离散化)
    NYOJ 129 树的判定 (并查集)
    NYOJ 117 求逆序数 (树状数组)
    NYOJ 93 汉诺塔 (数学)
    HDU 2050 折线分割平面 (数学)
    天梯赛L2-008 最长对称子串 (字符串处理)
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14383775.html
Copyright © 2011-2022 走看看