1. 程式人生 > 實用技巧 >【模版】生成樹計數

【模版】生成樹計數

無向圖生成樹計數(取模)

  • 圖中節點的下標從0開始計數!
  • 不存在生成樹返回-1
  • 不存在自環,允許存在重邊
typedef long long ll;
const ll mod = 998244353;

const int N = 105;
const int M = 1e4 + 5;

ll inv(ll a) {
    if(a == 1)return 1;
    return inv(mod%a)*(mod-mod/a)%mod;
}

struct Matrix {
    ll mat[N][N];
    void init() {
        memset(mat,0,sizeof(mat));
    }
    void addEdge(int u,int v) {
        mat[u][v]--;
        mat[u][u]++;
    }
    ll det(int n) { //求行列式的值模上MOD,需要使用逆元
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                mat[i][j] = (mat[i][j]%mod+mod)%mod;
        ll res = 1;
        for(int i = 0; i < n; i++) {
            for(int j = i; j < n; j++)
                if(mat[j][i]!=0) {
                    for(int k = i; k < n; k++)
                        swap(mat[i][k],mat[j][k]);
                    if(i != j)
                        res = (-res+mod)%mod;
                    break;
                }
            if(mat[i][i] == 0) {
                res = -1;//不存在(也就是行列式值為0)
                break;
            }
            for(int j = i+1; j < n; j++) {
                //int mut = (mat[j][i]*INV[mat[i][i]])%MOD;//打表逆元
                ll mut = (mat[j][i]*inv(mat[i][i]))%mod;
                for(int k = i; k < n; k++)
                    mat[j][k] = (mat[j][k]-(mat[i][k]*mut)%mod+mod)%mod;
            }
            res = (res * mat[i][i])%mod;
        }
        return res;
    }
}ret;

呼叫:

ret.init();
for (int i = 1; i <= m; i++) {
    scanf("%d%d%lld", &e[i].u, &e[i].v, &e[i].w);
    ret.addEdge(--e[i].u, --e[i].v);
    ret.addEdge(e[i].v, e[i].u);
}
ll tot = ret.det(n-1);
if(tot == -1) {
    puts("0");
    continue;
}