28
SCPC 1회 본선 - 트리 박현민 2017-07-18 1

[17.07.18] SCPC 1회 본선 - 트리

Embed Size (px)

Citation preview

Page 1: [17.07.18] SCPC 1회 본선 - 트리

SCPC 1회 본선 - 트리

박현민

2017-07-18 1

Page 2: [17.07.18] SCPC 1회 본선 - 트리

목차

문제

배경 지식

해법

코드

참고 문헌

2017-07-18 2

Page 3: [17.07.18] SCPC 1회 본선 - 트리

문제Chapter 1

2017-07-18 3

Page 4: [17.07.18] SCPC 1회 본선 - 트리

2017-07-18 4

문제

Page 5: [17.07.18] SCPC 1회 본선 - 트리

2017-07-18 5

문제 (Cont’d)

Page 6: [17.07.18] SCPC 1회 본선 - 트리

배경 지식Chapter 2

2017-07-18 6

Page 7: [17.07.18] SCPC 1회 본선 - 트리

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

Page 8: [17.07.18] SCPC 1회 본선 - 트리

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)

Page 9: [17.07.18] SCPC 1회 본선 - 트리

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

Page 10: [17.07.18] SCPC 1회 본선 - 트리

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

Page 11: [17.07.18] SCPC 1회 본선 - 트리

(-1)i+j × det(Mi,j) = Σw|STw| × xw

|MST| = minw|STw|

2017-07-18 11

Extension towards MST (Cont’d)

Page 12: [17.07.18] SCPC 1회 본선 - 트리

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)

Page 13: [17.07.18] SCPC 1회 본선 - 트리

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

Page 14: [17.07.18] SCPC 1회 본선 - 트리

해법Chapter 3

2017-07-18 14

Page 15: [17.07.18] SCPC 1회 본선 - 트리

Matrix M

For i in 1 ~ n– For j in i + 1 ~ n

• // Should make Mj,i to 0• (Row j) := Mi,i × (Row j) – Mj,i × (Row i)• 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)

Page 16: [17.07.18] SCPC 1회 본선 - 트리

앞에서 소개한 다항식 계산을 통해 MST를 구하는 방법은구현이 까다로울 것으로 예상됨

모든 간선을 가중치로 정렬 어떤 가중치 값에 대해 그 값으로만 구성되는 신장트리의

수 계산– 그 가중치 값보다 작은 모든 간선은 이미 연결된 것으로 처리

모두 곱하여 최소신장트리의 수 계산

2017-07-18 16

최소신장트리

Page 17: [17.07.18] SCPC 1회 본선 - 트리

모든 간선을 가중치로 정렬한 후 상한을 결정– 상한을 늘려가며 모두 연결되었는지 확인

상한 이내의 간선만 선택– 간선의 가중치는 더 이상 필요하지 않음

선택된 간선들만으로 이뤄진 신장트리의 수 계산

2017-07-18 17

최소병목신장트리

Page 18: [17.07.18] SCPC 1회 본선 - 트리

코드Chapter 4

2017-07-18 18

Page 19: [17.07.18] SCPC 1회 본선 - 트리

#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

전체 코드

Page 20: [17.07.18] SCPC 1회 본선 - 트리

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)

Page 21: [17.07.18] SCPC 1회 본선 - 트리

intcountSpanningTree(intn){

int i,j,k,t;longlongret=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;

}returnret;

}

2017-07-18 21

Determinant with O(n3) (Cont’d)

Page 22: [17.07.18] SCPC 1회 본선 - 트리

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;

}// answer = out

2017-07-18 22

최소신장트리

Page 23: [17.07.18] SCPC 1회 본선 - 트리

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;

}// answer = countSpanningTree(n)

2017-07-18 23

최소병목신장트리

Page 24: [17.07.18] SCPC 1회 본선 - 트리

참고 문헌Appendix

2017-07-18 24

Page 25: [17.07.18] SCPC 1회 본선 - 트리

https://en.wikipedia.org/wiki/Laplacian_matrix https://en.wikipedia.org/wiki/Kirchhoff%27s_theorem https://ko.wikipedia.org/wiki/%EB%9D%BC%ED%94%8C

%EB%9D%BC%EC%8A%A4_%EC%A0%84%EA%B0%9C

Konstantin Pieper(2008), “The Number of Spanning Trees in a Graph”, pp.4-8, http://wwwmayr.in.tum.de/konferenzen/Jass08/courses/1/pieper/Pieper_Paper.pdf

https://stackoverflow.com/a/38156436

2017-07-18 25

참고 문헌

Page 26: [17.07.18] SCPC 1회 본선 - 트리

Q&A

2017-07-18 26

Page 27: [17.07.18] SCPC 1회 본선 - 트리

감사합니다

2017-07-18 27

Page 28: [17.07.18] SCPC 1회 본선 - 트리

이 프레젠테이션은https://www.slideshare.net/525hm/170718-scpc-1에서 다시 보실 수 있습니다

2017-07-18 28