POJ 1737 Connected Graph (大数+递推)

题目链接:

http://poj.org/problem?id=1737

题意:

求 \(n\) 个点的无向简单连通图的个数。\((n<=50)\)

题解:

这题你甚至能OEIS。

http://oeis.org/A001187

但不支持这样做。TAT

间接做。

总方案数减去不合法方案。

因为\(n\)个点的完全图有 \(C(n,2)={n(n-1) \over 2}\) 条边,显然就有 \(2^{C(n,2)}\) 种子图,即枚举每条边是否选择。

设$ f[i]$ 表示每个点都和点 \(1\) 相连的连通图的个数 。

假设\(1\) 号点所在的连通块大小为 \(i\)。那么和 \(1\) 连通的这 \(i?1\) 个点就有 \(C(n-1,i-1)\) ,方案数则为:\(C(n-1,i-1)*f[i]\)。

然后其它 \(n?i\) 个点间任意连边即可,这时方案数为 \(2^{C(n-i,2)}\)。

综上,则存在递推式:

\[f[n]=2^{C(n,2)}-\sum_{i=1}^{n-1}f[i]*C(n-1,i-1)*2^{C(n-i,2)}\]

答案就是\(f[n]\)。

然后就套个大数板子。额...过世OJ好像不支持c++11。懒得改了,虽然不过,但代码是正确的。QAQ

代码:

#include <iostream>
#include <vector>
#include <cmath>
#include <complex>
#include <cstring>
#include <stdlib.h>
#include <string.h>
using namespace std;
typedef long long LL;
const double PI = acos(-1);
void rader(vector<complex<double> >& y) {
    int len = y.size();
    int i, j, k;
    for (i = 1, j = len / 2; i < len - 1; i++) {
        if (i < j) swap(y[i], y[j]);
        k = len / 2;
        while (j >= k) {
            j -= k;
            k /= 2;
        }
        if (j < k) j += k;
    }
}
void fft(vector<complex<double> >& y, int on) {
    int len = y.size();
    rader(y);
    for (int h = 2; h <= len; h <<= 1) {
        complex<double> wn(cos(-on * 2 * PI / h), sin(-on * 2 * PI / h));
        for (int j = 0; j < len; j += h) {
            complex<double> w(1, 0);
            for (int k = j; k < j + h / 2; k++) {
                complex<double> u = y[k];
                complex<double> t = w * y[k + h / 2];
                y[k] = u + t;
                y[k + h / 2] = u - t;
                w = w * wn;
            }
        }
    }
    if (on == -1) for (auto& i : y) i.real(i.real() / len);
}
class BigInt {
 private:
     string num;
     string sign;

 public:
     const string to_string() const {
         if (this->sign == "-") return this->sign + this->num;
         else return this->num;
     }
     const LL toll() { return stoll(this->to_string()); }
     const int toi() { return stoi(this->to_string()); }
     BigInt() : num("0"), sign("+") {}
     BigInt(const int t) {
         if (t < 0) {
             this->num = std::to_string(-t);
             this->sign = "-";
         } else {
             this->num = std::to_string(t);
             this->sign = "+";
         }
     }
     BigInt(const LL t) {
         if (t < 0) {
             this->num = std::to_string(-t);
             this->sign = "-";
         } else {
             this->num = std::to_string(t);
             this->sign = "+";
         }
     }
     BigInt(const string& t) {
         if (t[0] == '-') {
             this->num = t.substr(1);
             this->sign = "-";
         } else {
             this->num = t;
             this->sign = "+";
         }
         int flag = 0;
         while (flag < (int)this->num.length() - 1 && this->num[flag] == '0') flag++;
         this->num = this->num.substr(flag);
     }
     BigInt(char* const t) : BigInt(string(t)) {}
     friend bool operator< (const BigInt& t, const BigInt& s) {
         if (t.sign != s.sign) {
             if (t.sign == "-") return true;
             else return false;
         } else {
             if (t.sign == "-") {
                 if (t.num.length() == s.num.length()) {
                     return t.num > s.num;
                 } else {
                     return t.num.length() > s.num.length();
                 }
             } else {
                 if (t.num.length() == s.num.length()) {
                     return t.num < s.num;
                 } else {
                     return t.num.length() < s.num.length();
                 }
             }
         }
     }
     friend bool operator> (const BigInt& t, const BigInt& s) {
         return s < t;
     }
     friend bool operator== (const BigInt& t, const BigInt& s) {
         return t.num == s.num && t.sign == s.sign;
     }
     friend bool operator!= (const BigInt& t, const BigInt& s) {
         return !(t == s);
     }
     friend bool operator<= (const BigInt& t, const BigInt& s) {
         return t == s || t < s;
     }
     friend bool operator>= (const BigInt& t, const BigInt& s) {
         return t == s || t > s;
     }
     friend const BigInt abs(const BigInt& t) {
         BigInt ans = t;
         if (ans.sign == "-") ans.sign = "+";
         return ans;
     }
     friend const BigInt operator- (const BigInt& t) {
         BigInt ans = t;
         if (ans.sign == "-") ans.sign = "+";
         else ans.sign = "-";
         return ans;
     }
     friend istream& operator>> (istream& in, BigInt& t) {
         string s;
         in >> s;
         t = s;
         return in;
     }
     friend ostream& operator<< (ostream& out, const BigInt& t) {
         out << t.to_string();
         return out;
     }
     friend const BigInt operator+ (const BigInt& t, const BigInt& s) {
         BigInt ans, sub;
         if (t.num.length() < s.num.length()) {
             ans = s;
             sub = t;
         } else if (t.num.length() == s.num.length()) {
             if (t.num < s.num) {
                 ans = s;
                 sub = t;
             } else {
                 ans = t;
                 sub = s;
             }
         } else {
             ans = t;
             sub = s;
         }
         int sub_l = sub.num.length();
         int ans_l = ans.num.length();
         if (t.sign == s.sign) {
             for (int i = 1; i <= sub_l; i++) {
                 ans.num[ans_l - i] += sub.num[sub_l - i] - '0';
             }
             int flag = 0;
             for (int i = 1; i <= ans_l; i++) {
                 if (ans.num[ans_l - i] > '9') {
                     ans.num[ans_l - i] -= 10;
                     if (i == ans_l) {
                         flag = 1;
                     } else {
                         ans.num[ans_l - i - 1] += 1;
                     }
                 } else if (i >= sub_l) {
                     break;
                 }
             }
             if (flag) ans.num = "1" + ans.num;
         } else {
             for (int i = 1; i <= sub_l; i++) {
                 ans.num[ans_l - i] -= sub.num[sub_l - i] - '0';
             }
             for (int i = 1; i <= ans_l; i++) {
                 if (ans.num[ans_l - i] < '0') {
                     ans.num[ans_l - i] += 10;
                     ans.num[ans_l - i - 1] -= 1;
                 } else if (i >= sub_l) {
                     break;
                 }
             }
             int flag = 0;
             while (flag < ans_l - 1 && ans.num[flag] == '0') flag++;
             ans.num = ans.num.substr(flag);
             if (ans.num == "0") ans.sign = "+";
         }
         return ans;
     }
     friend const BigInt operator- (const BigInt& t, const BigInt& s) {
         BigInt sub = s;
         if (sub.sign == "+") sub.sign = "-";
         else sub.sign = "+";
         return t + sub;
     }
     friend const BigInt operator* (const BigInt& t, const BigInt& s) {
         BigInt res;
         if (s.sign == t.sign) res.sign = "+";
         else res.sign = "-";
         vector<complex<double> > x1, x2;
         vector<int> sum;
         string str1 = t.num, str2 = s.num;
         int len1 = str1.length();
         int len2 = str2.length();
         int len = 1;
         while (len < len1 * 2 || len < len2 * 2) len <<= 1;
         for (int i = 0; i < len1; i++) {
             x1.push_back(complex<double>(str1[len1 - 1 - i] - '0', 0));
         }
         for (int i = len1; i < len; i++) {
             x1.push_back(complex<double>(0, 0));
         }
         for (int i = 0; i < len2; i++) {
             x2.push_back(complex<double>(str2[len2 - 1 -i] - '0', 0));
         }
         for (int i = len2; i < len; i++) {
             x2.push_back(complex<double>(0, 0));
         }
         fft(x1, 1);
         fft(x2, 1);
         for (int i = 0; i < len; i++) x1[i] = x1[i] * x2[i];
         fft(x1, -1);
         for (auto& i : x1) sum.push_back((int)(i.real() + 0.5));
         for (int i = 0; i < len; i++) {
             sum[i + 1] += sum[i] / 10;
             sum[i] %= 10;
         }
         len = len1 + len2 - 1;
         while (sum[len] <= 0 && len > 0) len--;
         res.num = "";
         for (int i = len; i >= 0; i--) res.num += sum[i] + '0';
         if (res.num == "0") res.sign = "+";
         return res;
     }
     friend const BigInt operator/ (const BigInt& t, const BigInt& s) {
         if (s == 0) throw;
         BigInt res;
         if (s.sign == t.sign) res.sign = "+";
         else res.sign = "-";
         BigInt sub = abs(t), ans = abs(s);
         int w = sub.num.length() - ans.num.length();
         for (int i = 0; i < w; i++) ans.num += "0";
         while (w >= 0) {
             int d = 0;
             while (ans <= sub) {
                 sub -= ans;
                 d++;
             }
             res.num += d + '0';
             ans.num = ans.num.substr(0, ans.num.length() - 1);
             w--;
         }
         int flag = 0;
         while (flag < (int)res.num.length() - 1 && res.num[flag] == '0') flag++;
         res.num = res.num.substr(flag);
         if (res.num == "0") res.sign = "+";
         return res;
     }
     friend const BigInt operator% (const BigInt& t, const BigInt& s) {
         if (s == 0) throw;
         BigInt sub = abs(t), ans = abs(s);
         int w = sub.num.length() - ans.num.length();
         for (int i = 0; i < w; i++) ans.num += "0";
         while (w >= 0) {
             int d = 0;
             while (ans <= sub) {
                 sub -= ans;
                 d++;
             }
             w--;
             ans.num = ans.num.substr(0, ans.num.length() - 1);
         }
         sub.sign = t.sign;
         if (sub.num == "0") sub.sign = "+";
         return sub;
     }
     friend BigInt& operator+= (BigInt& t, const BigInt& s) {
         return t = t + s;
     }
     friend BigInt& operator-= (BigInt& t, const BigInt& s) {
         return t = t - s;
     }
     friend BigInt& operator*= (BigInt& t, const BigInt& s) {
         return t = t * s;
     }
     friend BigInt& operator/= (BigInt& t, const BigInt& s) {
         return t = t / s;
     }
     friend BigInt& operator%= (BigInt& t, const BigInt& s) {
         return t = t % s;
     }
     const BigInt subnum(int r, int l) {
         BigInt ans = this->num.substr(this->num.length() - l, l - r);
         ans.sign = this->sign;
         return ans;
     }
     const BigInt subnum(int l) {
         return this->subnum(0, l);
     }
};
BigInt dp[110][110];
void init()
{
    dp[0][0] = 1;
    for(int i = 1; i <= 51; i++) {
        dp[i][0] = 1;
        for(int j = 1; j <= i; j++) {
            dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
        }
    }
}
BigInt expo[2000];
BigInt f[52];
int main(int argc, char const *argv[]) {
    init();
    int n;
    expo[0] = 1;
    for(long long i = 1; i <= 1250; i++) {
        expo[i] = 2LL * expo[i - 1];
    }
    f[1] = 1;
    f[2] = 1;
    while(std::cin >> n) {
        if(n == 0) break;
        if(n <= 2) {
            std::cout << "1" << '\n';
            continue;
        }
        BigInt tmp = 0;
        for(int i = 3; i <= n; i++) {
            BigInt tot = expo[(i * (i - 1) >> 1)];
            // std::cout << "tot = " << tot << '\n';
            for(int j = 1; j <= i - 1; j++) {
                tot = tot - f[j] * dp[i - 1][j - 1] * expo[((i - j) * ((i - j) - 1)) >> 1];
            }
            f[i] = tot;
        }
        std::cout << f[n] << '\n';
    }
  return 0;
}

原文地址:https://www.cnblogs.com/LzyRapx/p/9111878.html

时间: 2024-11-05 11:49:55

POJ 1737 Connected Graph (大数+递推)的相关文章

poj 1737 Connected Graph

// poj 1737 Connected Graph // // 题目大意: // // 带标号的连通分量计数 // // 解题思路: // // 设f(n)为连通图的数量,g(n)为非连通图的数量,h(n)为所有的 // 图的数量,h(n) = 2 ^(n * (n - 1) / 2); // f(n) + g[n] = h(n). // // 考虑标号为1在哪个连通分量内,设连通分量内有k个点,则问题为 // 在n-1个点中选择k-1个点的方法数 C(n-1,k-1),此时1所在的连通图数

POJ 1737 Connected Graph 递推

题目大意:求n个点能组成多少种无向连通图 多年的老心病终于干掉了- - 令f[i]表示i个点能组成多少种无向图 首先易知我们能生成2^(i*(i-1)/2)种图 但是一些是不合法的 我们要将不合法的干掉 枚举1号节点与多少个点连通 设1号节点所在联通块大小为j(1<=j<=i-1) 那么与1相连的其它点有C(i-1,j-1)中选法,1号节点所在联通块有f[j]种连法,不与1号节点相连的点有2^((i-j)*(i-j-1)/2)种连法 故得到递推式f[i]=2^(i*(i-1)/2)-Σ[1&l

POJ 1737 Connected Graph 题解(未完成)

Connected Graph Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3156   Accepted: 1533 Description An undirected graph is a set V of vertices and a set of E∈{V*V} edges.An undirected graph is connected if and only if for every pair (u,v)

POJ 1205 Water Treatment Plants(递推)

题意   建设一条河岸的污水处理系统  河岸有n个城市   每个城市都可以自己处理污水 V   也可以把污水传到相邻的城市处理 >或<   除了你传给我我也传给你这种情况   其它都是合法的   两端的城市不能传到不存在的城市 令d[i]表示有i个城市时的处理方法数  最后一个城市的处理方法有 1.V 自己处理自己的  与前i-1个城市的处理方法无关  有d[i-1]种方法 2.< 给左边的城市去处理  也与前i-1个城市的处理方法无关  把自己的污水给第i-1个城市就行了  有d[i-

poj(1088)——滑雪(经典递推型动归)

题意: 中文题,就是在所有的点中找一个点作为起点,然后叫你找出从起点开始的最长路径是多少. 这里高度必须严格递减. 思路: 一开始我碰到这题时,没有思路,是看题解写的. 但是今天我回头再去看时,发现自己能够独立写出来了,而且和上次的方法不一样.也许这就是进步吧! 其实就是一个递推型动归,如果理解了上一题,那么这题也好做了. 这是第一次写的: #include<stdio.h> #include<string.h> #include<iostream> #include&

UVA 10254-The Priest Mathematician(大数+递推)

题目大意:在原本的汉诺塔游戏基础上加一根柱子,移动策略是:要移动N个汉诺塔,先用4根柱子把K个到一个柱子,然后用其余3根把剩下的N-K个移动到目标柱子,再用4根把初始的K个移动到目标柱子. 关键的问题是找到每个N的K是多少,观察可以发现规律是:随着K的递增,其实移动的次数Fn(K)先递增后递减,然后F1(K),F2(K),...的最大值随着K的增大递增.要形式化证明似乎比较困难..不过在题目的范围内这是可以AC的.程序中维护这个当前使得Fi(K)最大的K,然后递推. import java.ut

1sting 大数 递推

You will be given a string which only contains '1'; You can merge two adjacent '1' to be '2', or leave the '1' there. Surly, you may get many different results. For example, given 1111 , you can get 1111, 121, 112,211,22. Now, your work is to find th

UVa 10328 Coin Toss(Java大数+递推)

https://vjudge.net/problem/UVA-10328 题意: 有H和T两个字符,现在要排成n位的字符串,求至少有k个字符连续的方案数. 思路:这道题目和ZOJ3747是差不多的,具体做法可以参考另一篇博客http://www.cnblogs.com/zyb993963526/p/7203833.html 但是这道题目的话是要用大数来做的,c++感觉不太好写,就学了下java的做法. 1 import java.math.BigInteger; 2 import java.ut

【CF459E】Pashmak and Graph(递推+动规)

f[i]表示以边i结尾的最长路径,g[i]表示以点i结尾的最长路径,f[i]=g[e[i].u]+1.注意特判边权相等的情况,每次更新边连接的出度点的g即可. 推的话,数据范围3e5所以想到dp,而且必须是一维,固定一维枚举一维.所以边权排个序,枚举时就不用管边权递增的约束条件,只需要特判下相等的情况.状态和动态转移方程还是比较神仙(对我这种蒟蒻来说),拿结尾边和点做状态,学到就是赚到. #include<bits/stdc++.h> #define ri register int #defi