基尔霍夫矩阵题目泛做(AD第二轮)

题目1: SPOJ 2832

题目大意:

求一个矩阵行列式模一个数P后的值。p不一定是质数。

算法讨论:

因为有除法而且p不一定是质数,不一定有逆元,所以我们用辗转相除法。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <algorithm>
 6 
 7 using namespace std;
 8 
 9 const int N = 205;
10 typedef long long ll;
11 
12 int n;
13 ll p, mat[N][N];
14 
15 ll det(ll a[N][N]) {
16   ll res = 1;
17 
18   for(int i = 1; i <= n; ++ i) {
19     for(int j = i + 1; j <= n; ++ j) {
20       while(a[j][i]) {
21         ll t = a[i][i] / a[j][i];
22 
23         for(int k = i; k <= n; ++ k)
24           a[i][k] = (a[i][k] - a[j][k] * t) % p;
25         for(int k = i; k <= n; ++ k)
26           swap(a[i][k], a[j][k]);
27         res = -res;
28       }
29     }
30     if(a[i][i] == 0) return 0;
31     res = 1LL * res * a[i][i] % p;
32   }
33   return (res + p)  % p;
34 }
35 
36 int main() {
37   while(~scanf("%d%lld", &n, &p)) {
38     for(int i = 1; i <= n; ++ i) {
39       for(int j = 1; j <= n; ++ j) {
40         scanf("%lld", &mat[i][j]);
41         mat[i][j] %= p;
42       }
43     }
44     printf("%lld\n", det(mat));
45   }
46   return 0;
47 }
SPOJ 2832

 

题目2: BZOJ 1002 轮状病毒

题目大意:

一棵有规律的树,求其生成树的数量。基尔霍夫矩裸上。

关于矩阵树定理,有一个递推式: f[n] = 3 * f[n - 1] - f[n - 2] + 2;

高精度一下即可。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <algorithm>
  5 #include <iostream>
  6  
  7 using namespace std;
  8  
  9 const int rad = 10;
 10  
 11 int n;
 12  
 13 struct BigInt {
 14   int v[1005];
 15   int len;
 16  
 17   BigInt() {
 18     memset(v, 0, sizeof v);
 19     len = 0;
 20   }
 21  
 22   friend BigInt operator + (BigInt a, BigInt b) {
 23     int tmp = max(a.len, b.len);
 24  
 25     for(int i = 1; i <= tmp; ++ i) {
 26       a.v[i] += b.v[i];
 27       if(a.v[i] >= rad) {
 28         a.v[i + 1] += a.v[i] / rad;
 29         a.v[i] %= rad;
 30       }
 31     }
 32     while(a.v[tmp + 1]) tmp ++;
 33     a.len = tmp;
 34  
 35     return a;
 36   }
 37  
 38   friend BigInt operator * (BigInt a, BigInt b) {
 39     BigInt c;
 40     int tmp = a.len + b.len;
 41  
 42     for(int i = 1; i <= a.len; ++ i) {
 43       for(int j = 1; j <= b.len; ++ j) {
 44         c.v[i + j - 1] += a.v[i] * b.v[j];
 45       }
 46     }
 47     for(int i = 1; i <= tmp; ++ i) {
 48       if(c.v[i] >= rad) {
 49         c.v[i + 1] += c.v[i] / rad;
 50         c.v[i] %= rad;
 51       }
 52       if(c.v[i]) c.len = i;
 53     }
 54  
 55     return c;
 56   }
 57  
 58   friend BigInt operator * (BigInt a, int k) {
 59     for(int i = 1; i <= a.len; ++ i) {
 60       a.v[i] *= k;
 61     }
 62     for(int i = 1; i <= a.len; ++ i) {
 63       a.v[i + 1] += a.v[i] / rad;
 64       a.v[i] %= rad;
 65     }
 66     if(a.v[a.len + 1]) a.len ++;
 67     return a;
 68   }
 69  
 70   friend BigInt operator - (BigInt a, BigInt b) {
 71     for(int i = 1; i <= a.len; ++ i) {
 72       a.v[i] -= b.v[i];
 73       if(a.v[i] < 0) {
 74         a.v[i + 1] -= 1;
 75         a.v[i] += rad;
 76       }
 77     }
 78     while(a.v[a.len] == 0)a.len --;
 79     return a;
 80   }
 81   void getint(int k) {
 82     while(k) {
 83       v[++ len] = k % 10;
 84       k /= 10;
 85     }
 86   }
 87    
 88   void print() {
 89     for(int i = len; i >= 1; -- i) {
 90       printf("%d", v[i]);
 91     }
 92   }
 93 }f[105], cst;
 94  
 95 void Input() {
 96   scanf("%d", &n);
 97 }
 98  
 99 void Solve() {
100   f[1].getint(1);
101   f[2].getint(5);
102   cst.getint(2);
103   for(int i = 3; i <= n; ++ i) {
104     f[i] = f[i - 1] * 3 - f[i - 2] + cst;
105   }
106 }
107  
108 void Output() {
109   f[n].print();
110 }
111  
112 int main() {
113   Input();
114   Solve();
115   Output();
116  
117   return 0;
118 }
BZOJ 1002

 

题目3: SPOJ 104 HighWays

题目大意:

给一张图,求其生成树的个数。

算法讨论:裸上基尔霍夫。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <algorithm>
 6  
 7 using namespace std;
 8  
 9 typedef long long ll;
10 const int N = 15;
11  
12 ll ans;
13 int n, m;
14 ll degree[N][N], G[N][N], self[N][N];
15  
16 ll det(ll a[N][N]) {
17   ll res = 1;
18   
19   for(int i = 1; i < n; ++ i) {
20     for(int j = i + 1; j < n; ++ j) {
21       while(a[j][i]) {
22         ll t = a[i][i] / a[j][i];
23  
24         for(int k = i; k < n; ++ k)
25           a[i][k] = (a[i][k] - a[j][k] * t);
26         for(int k = i; k < n; ++ k)
27           swap(a[i][k], a[j][k]);
28         res = -res;
29       }
30     }
31     if(a[i][i] == 0) return 0;
32     res = 1LL * res * a[i][i];
33   }
34   return res;
35 }
36  
37 void Input() {
38   int x, y;
39  
40   memset(self, 0, sizeof self);
41   memset(degree, 0, sizeof degree);
42   
43   scanf("%d%d", &n, &m);
44   for(int i = 1; i <= m; ++ i) {
45     scanf("%d%d", &x, &y);
46     degree[x][y] ++;
47     degree[y][x] ++;
48     self[x][x] ++; self[y][y] ++;
49   }
50   for(int i = 1; i <= n; ++ i) {
51     for(int j = 1; j <= n; ++ j) {
52       G[i][j] = self[i][j] - degree[i][j];
53     }
54   }
55 }
56  
57 void Solve() {
58   ans = det(G);
59 }
60  
61 void Output() {
62   printf("%lld\n", ans);
63 }
64  
65 int main() {
66   int t;
67  
68   scanf("%d", &t);
69  
70   while(t --) {
71     Input();
72     Solve();
73     Output();
74   }
75  
76   return 0;
77 }
SPOJ 104

 

题目4: BZOJ 4031 [HEOI 2015] 小Z的房间

题目大意:并没有搞懂。只是抄的。河北的题还真是够呛。(PS:我是河北的)

算法讨论:裸上Matrix-Tree定理吧。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int N = 15;
 6 const int mod = 1e9;
 7 typedef long long ll;
 8 
 9 int n, m, cnt;
10 int p[N][N]; ll a[N * N][N * N];
11 int dx[]={0, 0, 1, -1};
12 int dy[]={1, -1, 0, 0};
13 char maze[N][N];
14 
15 ll det() {
16   ll res = 1;
17 
18   for(int i = 1; i < cnt; ++ i)
19     for(int j = 1; j < cnt; ++ j)
20       a[i][j] = (a[i][j] + mod) % mod;
21   for(int i = 1; i < cnt; ++ i) {
22     for(int j = i + 1; j < cnt; ++ j) {
23       while(a[j][i]) {
24         ll t = a[i][i] / a[j][i];
25         
26         for(int k = i; k < cnt; ++ k)
27           a[i][k] = (a[i][k] - a[j][k] * t % mod + mod) % mod;
28         for(int k = i; k < cnt; ++ k)
29           swap(a[i][k], a[j][k]);
30         res = -res;
31       }
32     }
33     if(a[i][i] == 0) return 0;
34     res = 1LL * res * a[i][i] % mod;
35   }
36   return (res + mod) % mod;
37 }
38 
39 int main() {
40   scanf("%d%d", &n, &m);
41   for(int i = 1; i <= n; ++ i) {
42     scanf("%s", maze[i] + 1);
43   }
44   for(int i = 1; i <= n; ++ i) 
45     for(int j = 1; j <= m; ++ j)
46       if(maze[i][j] == '.')
47         p[i][j] = ++ cnt;
48   for(int i = 1; i <= n; ++ i) {
49     for(int j = 1; j <= m; ++ j) {
50       if(maze[i][j] != '.') continue;
51       for(int k = 0; k < 4; ++ k) {
52         int nx = dx[k] + i, ny = dy[k] + j;
53 
54         if(nx < 1 || ny < 1 || nx > n || ny > m || maze[nx][ny] != '.') continue;
55         int u = p[i][j], v = p[nx][ny];
56 
57         a[u][u] ++; a[u][v] --;
58       }
59     }
60   }
61   printf("%lld\n", det());
62   return 0;
63 }
BZOJ 4031

 

题目5: Uva 10766

题目大意:

求一个有根树的生成树的数量。

算法讨论:

其实这个有根和无根是一样的。直接做就行。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 const int N = 55;
 7 
 8 int n, m, kk;
 9 bool lk[N][N];
10 ll a[N][N];
11 
12 ll det() {
13   ll res = 1;
14   
15   for(int i = 1; i < n; ++ i) {
16     for(int j = i + 1; j < n; ++ j) {
17       while(a[j][i]) {
18         ll t = a[i][i] / a[j][i];
19 
20         for(int k = i; k < n; ++ k)
21           a[i][k] = a[i][k] - a[j][k] * t;
22         for(int k = i; k < n; ++ k)
23           swap(a[i][k], a[j][k]);
24         res = -res;
25       }
26     }
27     if(a[i][i] == 0) return 0;
28     res = res * a[i][i];
29   }
30 
31   return abs(res);
32 }
33 
34 int main() {
35   int u, v;
36   
37   while(~scanf("%d%d%d", &n, &m, &kk)) {
38     memset(lk, false, sizeof lk);
39     memset(a, 0, sizeof a);
40     for(int i = 1; i <= m; ++ i) {
41       scanf("%d%d", &u, &v);
42       lk[u][v] = lk[v][u] = true;
43     }
44     for(int i = 1; i <= n; ++ i) {
45       int cnt = 0;
46 
47       for(int j = 1; j <= n; ++ j) {
48         if(i != j && !lk[i][j]) {
49           a[i][j] = -1;
50           ++ cnt;
51         }
52       }
53       a[i][i] = cnt;
54     }
55     printf("%lld\n", det());
56   }
57 
58   return 0;
59 }
Uva 10766

 

题目6: BZOJ1016 && JSOI2008最小生成树计数

题目大意:

求一个图的最小生成树的个数。

算法讨论:

将边权从小到大SORT。然后对于相同边权的做一次处理进行缩点。如果缩点后出现多个联通块,有两种方法:对每个联通块做Matrix-Tree,然后相乘,或者在两个联通块加一个桥,这样方案数不会受影响。

坑点就是最后如果有形不成树的情况。

代码:

  1 #include <cstdlib>
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <vector>
  7 
  8 using namespace std;
  9 const int N = 100 + 5;
 10 const int M = 1000 + 5;
 11 const int mod = 31011;
 12 typedef long long ll;
 13 
 14 int n, m, tim, cnt;
 15 ll A[N][N], ans = 1;
 16 int fa[N], lab[N], repos[N], f2[N];
 17 
 18 struct Edge {
 19     int u, v, d;
 20     bool operator < (const Edge &k) const {
 21         return d < k.d;
 22     }
 23 }e[M];
 24 vector <Edge> p[N];
 25 
 26 void Init() {
 27     scanf("%d%d", &n, &m);
 28     for(int i = 1; i <= m; ++ i) {
 29         scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].d);
 30     }
 31 }
 32 
 33 ll Det(ll a[N][N], int ns) {
 34     ll res = 1;
 35     for(int i = 1; i < ns; ++ i) {
 36         for(int j = i + 1; j < ns; ++ j) {
 37             while(a[j][i]) {
 38                 ll t = a[i][i] / a[j][i];
 39                 for(int k = i; k < ns; ++ k)
 40                     a[i][k] = (a[i][k] - a[j][k] * t);
 41                 for(int k = i; k < ns; ++ k)
 42                     swap(a[i][k], a[j][k]);
 43                 res = -res;
 44             }
 45         }
 46         if(a[i][i] == 0) return 0;
 47         res = res * a[i][i];
 48     }    
 49     return res;
 50 }
 51 
 52 int find(int *f, int x) {
 53     return f[x] == x ? x : (f[x] = find(f, f[x]));
 54 }
 55 
 56 void Work(vector <Edge> &v) {
 57     vector <Edge> :: iterator it;
 58     int poi = 0;
 59     ++ tim;
 60     for(it = v.begin(); it != v.end(); ++ it) {
 61         if(lab[fa[(*it).u]] != tim) {
 62             lab[fa[(*it).u]] = tim; 
 63             repos[fa[(*it).u]] = ++ poi;
 64         }
 65         if(lab[fa[(*it).v]] != tim) {
 66             lab[fa[(*it).v]] = tim;
 67             repos[fa[(*it).v]] = ++ poi;
 68         }
 69     }    
 70     for(int i = 1; i <= poi; ++ i) 
 71         for(int j = 1; j <= poi; ++ j)
 72             A[i][j] = 0;
 73     for(it = v.begin(); it != v.end(); ++ it) {
 74         -- A[repos[fa[(*it).u]]][repos[fa[(*it).v]]];
 75         -- A[repos[fa[(*it).v]]][repos[fa[(*it).u]]];
 76         ++ A[repos[fa[(*it).u]]][repos[fa[(*it).u]]];
 77         ++ A[repos[fa[(*it).v]]][repos[fa[(*it).v]]];
 78     }
 79     ans = ans * Det(A, poi) % mod;
 80 }
 81 
 82 void Calc(int l, int r) {
 83     for(int i = l; i <= r; ++ i) {
 84         f2[fa[e[i].u]] = fa[e[i].u];
 85         f2[fa[e[i].v]] = fa[e[i].v];
 86         p[fa[e[i].u]].clear();
 87         p[fa[e[i].v]].clear();
 88     }
 89     for(int i = l; i <= r; ++ i) {
 90         f2[find(f2, fa[e[i].u])] = find(f2, fa[e[i].v]);
 91     }
 92     for(int i = l; i <= r; ++ i) {
 93         if(fa[e[i].u] != fa[e[i].v]) {
 94             p[find(f2, fa[e[i].u])].push_back(e[i]);
 95         }
 96     }
 97     for(int i = l; i <= r; ++ i) {
 98         if(!p[fa[e[i].u]].empty()) {
 99             Work(p[fa[e[i].u]]), p[fa[e[i].u]].clear();
100         }
101         if(!p[fa[e[i].v]].empty()) {
102             Work(p[fa[e[i].v]]), p[fa[e[i].v]].clear();
103         }
104     }
105 }
106 
107 void Solve() {
108     sort(e + 1, e + m + 1);
109     cnt = n;
110     for(int i = 1; i <= n; ++ i) fa[i] = i;
111     for(int i = 1; i <= m && cnt > 1;) {
112         int j = i;
113         for(; e[j].d == e[i].d && j <= m; ++ j) {
114             find(fa, e[j].u); find(fa, e[j].v);
115         }
116         Calc(i, j - 1);
117         for(int k = i; k < j; ++ k) {
118             int fx = find(fa, e[k].u), fy = find(fa, e[k].v);
119             if(fx != fy) {
120                 fa[fx] = fy;
121                 cnt --;
122             }
123         }
124         i = j;
125     }
126     if(cnt != 1) ans = 0;
127     printf("%lld\n", ans % mod);
128 }
129 
130 #define stone_eee
131 int main() {
132 #ifndef stone_
133     freopen("mst.in", "r", stdin);
134     freopen("mst.out", "w", stdout);
135 #endif
136 
137     Init();
138     Solve();
139 
140 #ifndef stone_
141     fclose(stdin); fclose(stdout);
142 #endif
143     return 0;
144 }
1016

 

posted @ 2016-04-12 09:38  漫步者。!~  阅读(338)  评论(0编辑  收藏  举报