• bzoj 1005: [HNOI2008]明明的烦恼 prufer编号&&生成树计数


    1005: [HNOI2008]明明的烦恼

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 2248  Solved: 898
    [Submit][Status]

    Description

    自从明明学了树的结构,就对奇怪的树产生了兴趣...... 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树?

    Input

    第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1

    Output

    一个整数,表示不同的满足要求的树的个数,无解输出0

    Sample Input

    3
    1
    -1
    -1

    Sample Output

    2

    HINT

    两棵树分别为1-2-3;1-3-2

    Source

    生成树prufer标号

      首先选这棵树叶子中编号最小的点,将这个点删除,并且把它的邻接点加入一个数组中,例如第一个删除的节点为1,并且把5加入数组中。删除节点后形成一棵新的树,再在新树中删除最小的节点,并且把邻接点加入数组中,,这样重复以上步骤,知道树中最后剩余两个点的时候终止操作。这时候数组中的便是prufer编码。

     

    生成树prufer标号的性质(觉得相当神奇啊):

       1.prufer序列和树一一对应。

       2.序列的长度=树的节点个数-2。

       3.树中该节点的度数=该节点编号在序列中出现的次数+1,叶子节点不会出现在序列中。

    每一个标号有且仅有一个对应的生成树。

    有些时候当计数问题不含加减,但含除法时,可通过分解质因数简化。

    而且光靠想出来的公式很不靠谱的。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define MAXN 1010
    #define MAXL 1000
    #define VAL1 10000
    class number//四位
    {
            public:
                    number()
                    {
                            clear();
                    }
                    bool is_odd()
                    {
                            return numb[0]%2==1;
                    }
                    bool is_even()
                    {
                            return numb[0]%2==0;
                    }
                    void lsh_bin()
                    {
                            int i;
                            for (i=topn;i>0;i--)
                            {
                                    if (numb[i]%2==1)
                                    {
                                            numb[i-1]+=VAL1;
                                    }
                                    numb[i]/=2;
                            }
                            numb[0]/=2;
                            while (topn&&!numb[topn])topn--;
                    }
                    bool equal_to(int x)
                    {
                            if (topn==0)
                            {
                                    return x==numb[0];
                            }
                            if (topn==1)
                            {
                                    return x==numb[0]+numb[1]*VAL1;
                            }
                            return false;
                    }
                    int size()
                    {
                            return topn;
                    }
                    int length()
                    {
                            int x=numb[topn];
                            int ret=0;
                            while (x)
                            {
                                    ret++;
                                    x/=10;
                            }
                            int y=0;
                            x=VAL1;
                            while (x)
                            {
                                    y++;
                                    x/=10;
                            }
                            y--;
                            ret+=topn*y;
                            return ret;
                    }
                    void operator =(int x)//{{{
                    {
                            int now=0;
                            clear();
                            numb[now]=x;
                            while (numb[now]>=VAL1)
                            {
                                    numb[now+1]+=numb[now]/VAL1;
                                    numb[now]%=VAL1;
                                    now++;
                                    if (now>topn)topn=now;
                            }
                    }//}}}
    void operator =(number num)//{{{
    {
            topn=num.topn;
            memcpy((this->numb),num.numb,sizeof(num.numb[0])*(topn+1));
    }//}}}
    void operator +=(number &num)//{{{
    {
            int i;
            topn=max(topn,num.topn);
            for (i=0;i<=topn;i++)
            {
                    numb[i]+=num.numb[i];;
                    if (numb[i]>=VAL1)
                    {
                            numb[i+1]+=numb[i]/VAL1;
                            numb[i]%=VAL1;
                    }
            }
            while (numb[topn+1])
            {
                    topn++;
                    numb[topn+1]+=numb[topn]/VAL1;
                    numb[topn]%=VAL1;
            }
    }//}}}
    void operator +=(int x)//{{{
    {
            int now=0;
            if (topn==-1)topn=0;
            numb[now]+=x;
            while (numb[now]>=VAL1)
            {
                    numb[now+1]+=numb[now]/VAL1;
                    numb[now]%=VAL1;
                    now++;
                    if (now>topn)topn=now;
            }
    }//}}}
    void operator *=(int x)//{{{
    {
            int i;
            for (i=0;i<=topn;i++)
            {
                    numb[i]*=x;
            }
            for (i=0;i<=topn;i++)
            {
                    if (numb[i]>=VAL1)
                    {
                            numb[i+1]+=numb[i]/VAL1;
                            numb[i]%=VAL1;
                    }
            }
            while (numb[topn+1])
            {
                    topn++;
                    numb[topn+1]+=numb[topn]/VAL1;
                    numb[topn]%=VAL1;
            }
    }//}}}
    void operator *=(number &num)
    {
            number ret;
            ret=(*this)*num;
            (*this)=ret;
    }
    void operator -=(number &num)//{{{
    {
            if (*this<num)throw "Error!
    ->void operator -=(number &num)
    ";
            int i;
            for (i=0;i<=topn;i++)
            {
                    numb[i]-=num.numb[i];
            }
            for (i=0;i<=topn;i++)
            {
                    while (numb[i]<0)
                    {
                            numb[i]+=VAL1;
                            numb[i+1]--;
                    }
            }
            while (topn&&!numb[topn])topn--;
    }//}}}
    void operator /=(int x)
    {
            int i;
            int tot=0;
            for (i=topn;i>=0;i--)
            {
                    tot=tot*VAL1+numb[i];
                    numb[i]=tot/x;
                    tot%=x;
            }
            while (topn&&!numb[topn])topn--;
    }
    void operator --(int)//{{{
    {
            if (topn==0&&numb[0]==0)throw "Error!
    ->void operator --(int)
    ";
            int now=0;
            numb[now]--;
            while (numb[now]<0)
            {
                    numb[now+1]--;
                    numb[now]+=VAL1;
            }
            while (topn&&!numb[topn])topn--;
    }//}}}
    private:
    int numb[MAXL];
    int topn;
    void clear()
    {
            topn=0;
            memset(numb,0,sizeof(numb));
    
    }
    friend bool operator <(number num1,number num2);
    friend bool operator <=(number num1,number num2);
    friend bool operator ==(number num1,number num2);
    friend ostream& operator <<(ostream &out,number &num);
    friend istream& operator >>(istream &in,number &num);
    friend number operator *(number &num1,number &num2);
    friend number operator *(number num,int x);
    friend number operator +(number num1,number num2);
    friend number operator +(number num1,int x);
    friend number operator -(number num1,number num2);
    //a=a+b远没有a+=b快
    };
    bool operator <(number num1,number num2)//{{{
    {
            if (num1.topn!=num2.topn)
            {
                    return num1.topn<num2.topn;
            } 
            int i;
            for (i=num1.topn;i>=0;i--)
            {
                    if (num1.numb[i]!=num2.numb[i])
                    {
                            return num1.numb[i]<num2.numb[i];
                    }
            }
            return false;
    }//}}}
    bool operator <=(number num1,number num2)//{{{
    {
            if (num1.topn!=num2.topn)
            {
                    return num1.topn<num2.topn;
            } 
            int i;
            for (i=num1.topn;i>=0;i--)
            {
                    if (num1.numb[i]!=num2.numb[i])
                    {
                            return num1.numb[i]<num2.numb[i];
                    }
            }
            return true;
    }//}}}
    bool operator ==(number num1,number num2)//{{{
    {
            if (num1.topn!=num2.topn)return false;
            for (int i=0;i<=num1.topn;i++)
            {
                    if (num1.numb[i]!=num2.numb[i])return false;
            }
            return true;
    }//}}}
    ostream& operator <<(ostream &out,number &num)//{{{
    {
            int i;
            out<<num.numb[num.topn];
            for (i=num.topn-1;i>=0;i--)
            {
                    //压六位时
                    //        if (num.numb[i]<100000)out<<"0";
                    //        if (num.numb[i]<10000)out<<"0";
                    if (num.numb[i]<1000)out<<"0";
                    if (num.numb[i]<100)out<<"0";
                    if (num.numb[i]<10)out<<"0";
                    out<<num.numb[i];
            }
            return out;
    }//}}}
    istream& operator >>(istream &in,number &num)//{{{
    {
            string str;
            in>>str;
            int i;
            num.clear();
            for (i=(int)str.length()-1,num.topn=0;i>=0;i-=4,num.topn++)
            {
                    if (i-3<str.length())
                    {
                            num.numb[num.topn]=(str[i]-'0')+10*(str[i-1]-'0')+100*(str[i-2]-'0')+1000*(str[i-3]-'0');
                    }else
                    {
                            if (i-2<str.length())num.numb[num.topn]+=100*(str[i-2]-'0');
                            if (i-1<str.length())num.numb[num.topn]+=10*(str[i-1]-'0');
                            if (i  <str.length())num.numb[num.topn]+=(str[i]-'0');
                    }
            }
            num.topn--;
            return in;
    }//}}}
    number operator *(number num,int x)//{{{
    {
            number ret;
            ret=num;
            ret*=x;
            return ret;
    }//}}}
    number operator * (number &num1,number &num2)
    {
            int i,j;
            number ret;
            ret.topn=num1.topn+num2.topn;
            for (i=0;i<=num1.topn;i++)
            {
                    for (j=0;j<=num2.topn;j++)
                    {
                            ret.numb[i+j]+=num1.numb[i]*num2.numb[j];
                            if (ret.numb[i+j]>=VAL1)
                            {
                                    ret.numb[i+j+1]+=ret.numb[i+j]/VAL1;
                                    ret.numb[i+j]%=VAL1;
                            }
                    }
            }
            for (i=0;i<=ret.topn;i++)
            {
                    if (ret.numb[i]>=VAL1)
                    {
                            ret.numb[i+1]+=ret.numb[i]/VAL1;
                            ret.numb[i]%=VAL1;
                    }
            }
            while (ret.numb[ret.topn+1])
            {
                    ret.topn++;
                    ret.numb[ret.topn+1]+=ret.numb[ret.topn]/VAL1;
                    ret.numb[ret.topn]%=VAL1;
            }        
            return ret;
    }
    number operator +(number num1,number num2)//{{{
    {
            number ret;
            ret=num1;
            ret+=num2;
            return ret;
    }//}}}
    number operator +(number num1,int x)//{{{
    {
            number ret;
            ret=num1;
            ret+=x;
            return ret;
    }//}}}
    number operator -(number num1,number num2)//{{{
    {
            number ret;
            ret=num1;
            ret-=num2;
            return ret;
    }//}}}
    number c (int x,int y)
    {
            number ret;
            ret=1;
            int i;
            for (i=y+1;i<=x;i++)
                    ret*=i;
            for (i=1;i<=(x-y);i++)
                    ret/=i;
            return ret;
    }
    int main()
    {
            freopen("input.txt","r",stdin);
            int x;
            int n;
            scanf("%d",&n);
            number ans;
            number temp1,temp2,temp3;
    //        number temp;
    //        temp=c(1000,2);
    //        cout<<temp<<endl;
            ans=1;
            int r=n-2;
            int i,j;
            j=1;
            int totu=0;
            for (i=0;i<n;i++)
            {
                    scanf("%d",&x);
                    if (x==0)
                    {
                            printf("0
    ");
                            return 0;
                    }
                    if (x!=-1)
                    {
                            if (!r&&x-1)
                            {
                                    printf("0
    ");
                                    return 0;
                            }
                            temp1=c(r,x-1);
                            ans*=temp1;
                            r-=x-1;
                            if (r<0)
                            {
                                    printf("0
    ");
                                    return 0;
                            }
                    }else
                    {
                            totu++;
                    }
            }
            if (r&&totu<=0)
            {
                    printf("0
    ");
                    return 0;
            }
            if (r)
            {
                    for (i=1;i<=r;i++)
                    {
                            ans=ans*totu;
                    }
            }
            cout<<ans<<endl;
    }
    by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

    本博客已停用,新博客地址:http://mhy12345.xyz

  • 相关阅读:
    剑指offer题解(python版)(更新到第16题)
    Java基础知识详解:值传递
    [LeetCode] 583. Delete Operation for Two Strings
    [LeetCode] 856. Score of Parentheses
    [LeetCode] 1129. Shortest Path with Alternating Colors
    [LeetCode] 1561. Maximum Number of Coins You Can Get
    [LeetCode] 1052. Grumpy Bookstore Owner
    [LeetCode] 991. Broken Calculator
    [LeetCode] 1054. Distant Barcodes
    [LeetCode] 1245. Tree Diameter
  • 原文地址:https://www.cnblogs.com/mhy12345/p/3861663.html
Copyright © 2020-2023  润新知