description
給乙個n個點的無向連通圖,求每條邊被多少個極小割邊集包括
input
第一行一整數t表示用例組數,每組用例首先輸入兩個整數n和m表示點數和邊數,之後m行每行兩個整數u和v表示u,v之間有一條邊
(t<=20,2<=n<=20,n-1<=m<=n*(n-1)/2)
output
對於每組用例,輸出m個整數表示每條邊被多少個極小割邊集包括
sample input
2 3 3
0 1
0 2
1 2
3 2
0 1
0 2
sample output
case #1: 2 2 2
case #2: 1 1
solution
極小割邊集會把整張圖分成兩個連通塊,因為至多20個點,所以可以用乙個20位的二進位制數表示乙個點集,首先找出所有連通點集,由於每個連通點集必然可以拿出乙個點與剩餘點有邊且剩餘點連通,故可以從乙個點的點集開始轉移求出所有連通點集,具體操作看**,關鍵是求出任一點集的鄰接點,然後從乙個連通點集開始,往其中加入這個點集的某個鄰接點以及和這個鄰接點可達的點就可以構成乙個新的連通點集,這個通過乙個bfs可以實現,然後我們就得到了所有點集的連通狀態,對於某個點集i,如果i是連通的而且i的補集j是連通的,那麼說明i和j之間連的所有邊構成乙個極小割邊集,對這些割邊集一一更新答案顯然不行,我們可以採用對總體累加,對不合法情況累加,然後讓兩者相減得到答案,換句話說,對於邊u->v,其答案=u和v處於兩個不同且互補的連通點集的方法數=(兩個連通點集互補的方法數tot-u和v屬於同乙個連通點集中的方法數)/2,右邊第一項可以列舉所有點集i,如果i和它的補集j都是連通的則tot++,sum[i]++,sum[j]++,sum[i]++說明i這個點集中任意兩點處於同乙個連通點集的方法數加一,這樣做一遍後我們得到了右邊第一項tot,但是u和v處於同乙個連通點集的方法數還沒有得到,考慮到所有包含u和v的點集都是點集的超集,因此可以對sum陣列用一遍高維字首和,那麼sum[(1<< u)|(1<< v)]即為右邊第二項
code
#include
#include
#include
using namespace std;
#define maxn 1111111
int t,n,m,u[222],v[222],reach[maxn],q[maxn],mask[maxn],sum[maxn],tot,case=1;
int lowbit(int
x)int main()
}for(int i=0;i<1
<1)^i;
if(mask[i]&&mask[j])sum[i]++,sum[j]++,tot++;
}//高維字首和
for(int j=0;jfor(int i=(1
<1;i>=0;i--)
if(!(i&(1
<1
//u->v這條邊作為割邊的次數(總數-包含u和v的連通塊數)/2
for(int i=1;i<=m;i++)
printf(" %d",(tot-sum[(1
<1
<2);
printf("\n");
}return
0;}
高維字首和
給定 num 個三元組 x,y,z 每次詢問滿足 x leq qx y leq qy z leq qz 的三元組個數。x,y,z leq n n leq 10 q num leq 10 6 容易想到維護 pre x,y,z 表示 x leq x y leq y z leq z 的三元組個數 思路1利...
學習筆記 高維字首和
求 sum i n i a i 實際上,這只是高維字首和的一種特殊形式,即每一維的大小都為 2.我們計算矩陣字首和時,通常用的是容斥的方法.設當前要計算 d 維字首和,容斥的複雜度為 sum n binom 2 d 當維數過大時顯然不行.我們考慮計算矩陣字首和的另一種方法 先算出每一列的字首和,然後...
codeforces 938F(dp 高維字首和)
題意 給乙個長度為n的字串,定義 k floor 一共k輪操作,第i次操作要刪除當前字串恰好長度為 2 的子串 問最後剩餘的字串字典序最小是多少?分析 首先很容易得到乙個性質,那就是刪除的那些串是可以不交叉的 很容易想到乙個很簡單的dp dp i j 表示考慮原串的前i位,刪除狀態為j的情況下字典序...