帶邊數的無向連通圖計數


就是求 \(n\) 個點 \(m\) 條邊的帶標號無向連通圖個數。

首先可以用最暴力的 \(O(n^6)\) 做法,直接按城市規划一題的容斥 DP 做法,
\(f_{n,m}\) 表示答案,可以枚舉 \(1\) 號點所在塊的情況容斥計算。

\(O(n^4)\) 做法是一個有意思的斯特林反演。

考慮一個選了 \(m\) 條邊的方案,且形成 \(k\) 個連通塊方案塊的方案是 \(F_{m,k}\)
現在我們還是 \(m\) 條邊,但人為划分出來 \(j\) 個塊一定不兩兩相連,但塊內任意連邊,方案是 \(G_{m,j}\)

有組合關系:

\[G_{m,k} = \sum_{j\ge k} S2(j, k) F_{m,j} \]

反演以后即:

\[F_{m,k} = \sum_{j\ge k} S1(j, k) (-1)^{j - k} G_{m,j} \]

我們要求的即:

\[F_{m,1} = \sum_{j\ge 1} (j - 1)! (-1)^{j - 1} G_{m,j} \]

考慮 DP 后面那個 \(G\),暴力大概不止 \(O(n^6)\)
但是我們發現算這個 \(G\) 只需要知道塊的划分情況,那么這 \(m\) 條邊的可以隨意選取。
\(H_{i,j,m}\) 表示 DP 了 \(i\) 個點,分了 \(j\) 個塊,當前共有 \(m\) 個邊可以用的方案數。

則有:

\[G_{m,j}=\sum_{k\ge m} H_{n,j,k} {k\choose m} \]

直接 DP 這個 H 復雜度過高,接下來嘗試縮去中間 \(j\) 那一維。
現在考慮把 \((j - 1)! (-1)^{j - 1}\) 的附加貢獻在 DP 過程中算上,
發現我們可以先正常選一個塊,並固定這個塊的一號在最前面,
然后剩下的每加入一個塊,帶一個 \(-1\) 的系數並且把這個塊的點任意插進去(只需保證不在開頭,系數 \(i + k - 1\choose k\))進行 DP。
這樣就做到讓一個 \(k\) 個塊的方案會算重 \((k - 1)!\) 次。
時間復雜度 \(O(n^4)\)

然而代碼短小精悍。

void DP()
{
	for(int i = 1; i <= n; ++i)
		H[i][c2(i)] = 1;
	for(int i = 1; i <= n; ++i)
		for(int j = c2(i); j >= 0; --j)
			if(H[i][j])
				for(int k = 1; i + k <= n; ++k)
					H[i + k][j + c2(k)] = (H[i + k][j + c2(k)] - 1ll * H[i][j] * C[i + k - 1][k]) % mod;
	for(int j = 0; j <= c2(n); ++j)
	{
		for(int k = j; k <= c2(n); ++k)
			F[j] = (F[j] + 1ll * H[n][k] * C[k][j]) % mod;
		F[j] = (F[j] + mod) % mod;
		printf("%d\n", F[j]);
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM