7. Laplacian matrix L
Degree matrix D
Adjacency matrix A
L = D – A
Li,j
– deg(vi) if i = j
– -1 if i ≠ j and vi is adjacent to vj
– 0 otherwise
2017-07-18 7
Laplacian matrix
8. Incidence matrix I
Ii,j
– 1 if ej ends in i
– -1 if ej starts in i
– 0 otherwise
L = I × IT
2017-07-18 8
Laplacian matrix (Cont’d)
9. L’s i, j minor matrix Mi,j
|ST| = (L’s (i,j)-cofactor) = (-1)i+j × det(Mi,j)
2017-07-18 9
Kirchhoff’s matrix tree theorem
10. Ii,j
– xw(i,j) if ej ends in i
– -xw(i,j) if ej starts in i
– 0 otherwise
L = I × IT
Li,j
– Σkxw(i,k) if i = j
– -xw(i,j) if i ≠ j and vi is adjacent to vj
– 0 otherwise
2017-07-18 10
Extension towards MST
12. Gaussian elimination
– B is a matrix obtained by multiplying a row of A by some
non-zero constant ß
• det(A)= ß-1 * det(B)
– B is a matrix obtained by adding a multiple of one row to
another row in A
• det(A)= det(B)
Row echelon form matrix R
det(R) = ΠiRi,i
2017-07-18 12
Determinant with O(n3)
13. 1000000007 is prime
ap-1 ≡ 1 (mod p)
a-1 ≡ ap-2 (mod p)
O(log p)
2017-07-18 13
Inverse in modulo operation
15. Matrix M
For i in 1 ~ n
– For j in i + 1 ~ n
• // Shouldmake Mj,i to 0
• (Rowj) := Mi,i × (Rowj) – Mj,i × (Rowi)
• det = Mi,i
-1 × det
// M is now in row echelon form
det = det × ΠiMi,i
2017-07-18 15
Determinant with O(n3) (Cont’d)
16. 앞에서 소개한 다항식 계산을 통해 MST를 구하는 방법은
구현이 까다로울 것으로 예상됨
모든 간선을 가중치로 정렬
어떤 가중치 값에 대해 그 값으로만 구성되는 신장트리의
수 계산
– 그 가중치 값보다 작은 모든 간선은 이미 연결된 것으로 처리
모두 곱하여 최소신장트리의 수 계산
2017-07-18 16
최소신장트리
17. 모든 간선을 가중치로 정렬한 후 상한을 결정
– 상한을 늘려가며 모두 연결되었는지 확인
상한 이내의 간선만 선택
– 간선의 가중치는 더 이상 필요하지 않음
선택된 간선들만으로 이뤄진 신장트리의 수 계산
2017-07-18 17
최소병목신장트리
19. #pragma warning(disable:4786)
#include<iostream>
using namespace std;
#include<algorithm>
#include<set>
#include<vector>
#include<memory.h>
struct S
{
int x,y,v;
bool operator()(S a,S b)
{
return a.v<b.v;
}
}a[1010];
int t,n,m,d[110][110],p[110],c[110],cnt;
set<int> s;
vector<pair<int,int> > v[110];
int getDivisor(int a)
{
int i;
long long b[40]={a},ret=1;
for(i=1;i<=30;++i)b[i]=(b[i-1]*b[i-1])%1000000007;
for(i=0;i<=30;++i)if((1<<i)&1000000005)ret=(ret*b[i]+1000000007)%1000000007;
return ret;
}
int countSpanningTree(int n)
{
int i,j,k,t;
long long ret=1;
for(i=2;i<=n;++i)
{
if(d[i][i]==0)continue;
for(j=i+1;j<=n;++j)
{
if(d[j][i]==0)continue;
t=d[j][i];
for(k=i;k<=n;++k)d[j][k]=d[i][i]*d[j][k]-t*d[i][k];
ret=(ret*getDivisor(d[i][i]))%1000000007;
}
ret=(ret*d[i][i]+1000000007)%1000000007;
}
return ret;
}
int uf(int v)
{
if(p[v]==v)return v;
else return p[v]=uf(p[v]);
}
void dfs(int p,int mxv)
{
int i;
c[p]=cnt;
for(i=0;i<v[p].size();++i)if(!c[v[p][i].first]&&v[p][i].second<=mxv)dfs(v[p][i].first,mxv);
}
inline int mn2(int a,int b)
{
if(a>b)return b;
else return a;
}
int main()
{
int i,j,k,l,next;
long long out;
set<int>::iterator it;
cin.sync_with_stdio(false);
cin>>t;
for(i=1;i<=t;++i)
{
cin>>n>>m;
for(j=1;j<=n;++j)v[j].clear();
for(j=1;j<=m;++j)
{
cin>>a[j].x>>a[j].y>>a[j].v;
v[a[j].x].push_back(make_pair(a[j].y,a[j].v));
v[a[j].y].push_back(make_pair(a[j].x,a[j].v));
}
out=1;
sort(&a[1],&a[m+1],S());
for(j=1;j<=m;j=next)
{
for(next=j+1;next<=m;++next)if(a[next].v!=a[j].v)break;
memset(c,0,sizeof(c));
cnt=0;
for(k=1;k<=n;++k)
{
if(c[k])continue;
for(l=0;l<v[k].size();++l)if(v[k][l].second<a[j].v)break;
if(l<v[k].size())
{
++cnt;
dfs(k,a[j].v-1);
}
}
s.clear();
for(k=j;k<next;++k)
{
s.insert(a[k].x);
s.insert(a[k].y);
}
for(it=s.begin();it!=s.end();++it)if(!c[*it])c[*it]=++cnt;
memset(d,0,sizeof(d));
for(k=j;k<next;++k)
{
d[c[a[k].x]][c[a[k].x]]++;
d[c[a[k].y]][c[a[k].y]]++;
d[c[a[k].x]][c[a[k].y]]--;
d[c[a[k].y]][c[a[k].x]]--;
}
out=(out*countSpanningTree(cnt)+1000000007)%1000000007;
}
for(j=1;j<=n;++j)p[j]=j;
for(j=1;j<=m;j=next)
{
for(next=j+1;next<=m;++next)if(a[next].v!=a[j].v)break;
for(k=j;k<next;++k)p[a[k].x]=uf(a[k].y);
for(k=1;k<=n;++k)if(uf(k)!=uf(1))break;
if(k>n)continue;
}
memset(d,0,sizeof(d));
for(j=1;j<next;++j)
{
d[a[j].x][a[j].x]++;
d[a[j].y][a[j].y]++;
d[a[j].x][a[j].y]=-1;
d[a[j].y][a[j].x]=-1;
}
cout<<"Case #"<<i<<endl<<(int)out<<" "<<countSpanningTree(n)<<endl;
}
return 0;
}
2017-07-18 19
전체 코드
20. int getDivisor(int a)
{
int i;
long long b[40]={a},ret=1;
for(i=1;i<=30;++i)b[i]=(b[i-1]*b[i-1])%1000000007;
for(i=0;i<=30;++i)if((1<<i)&1000000005)ret=(ret*b[i]
+1000000007)%1000000007;
return ret;
}
2017-07-18 20
Inverse in modulo operation (Cont’d)