基尔霍夫矩阵题目泛做(AD第二轮)
题目1: SPOJ 2832
题目大意:
求一个矩阵行列式模一个数P后的值。p不一定是质数。
算法讨论:
因为有除法而且p不一定是质数,不一定有逆元,所以我们用辗转相除法。
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm> using namespace std; const int N = ;
typedef long long ll; int n;
ll p, mat[N][N]; ll det(ll a[N][N]) {
ll res = ; for(int i = ; i <= n; ++ i) {
for(int j = i + ; j <= n; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i]; for(int k = i; k <= n; ++ k)
a[i][k] = (a[i][k] - a[j][k] * t) % p;
for(int k = i; k <= n; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = 1LL * res * a[i][i] % p;
}
return (res + p) % p;
} int main() {
while(~scanf("%d%lld", &n, &p)) {
for(int i = ; i <= n; ++ i) {
for(int j = ; j <= n; ++ j) {
scanf("%lld", &mat[i][j]);
mat[i][j] %= p;
}
}
printf("%lld\n", det(mat));
}
return ;
}
SPOJ 2832
题目2: BZOJ 1002 轮状病毒
题目大意:
一棵有规律的树,求其生成树的数量。基尔霍夫矩裸上。
关于矩阵树定理,有一个递推式: f[n] = 3 * f[n - 1] - f[n - 2] + 2;
高精度一下即可。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream> using namespace std; const int rad = ; int n; struct BigInt {
int v[];
int len; BigInt() {
memset(v, , sizeof v);
len = ;
} friend BigInt operator + (BigInt a, BigInt b) {
int tmp = max(a.len, b.len); for(int i = ; i <= tmp; ++ i) {
a.v[i] += b.v[i];
if(a.v[i] >= rad) {
a.v[i + ] += a.v[i] / rad;
a.v[i] %= rad;
}
}
while(a.v[tmp + ]) tmp ++;
a.len = tmp; return a;
} friend BigInt operator * (BigInt a, BigInt b) {
BigInt c;
int tmp = a.len + b.len; for(int i = ; i <= a.len; ++ i) {
for(int j = ; j <= b.len; ++ j) {
c.v[i + j - ] += a.v[i] * b.v[j];
}
}
for(int i = ; i <= tmp; ++ i) {
if(c.v[i] >= rad) {
c.v[i + ] += c.v[i] / rad;
c.v[i] %= rad;
}
if(c.v[i]) c.len = i;
} return c;
} friend BigInt operator * (BigInt a, int k) {
for(int i = ; i <= a.len; ++ i) {
a.v[i] *= k;
}
for(int i = ; i <= a.len; ++ i) {
a.v[i + ] += a.v[i] / rad;
a.v[i] %= rad;
}
if(a.v[a.len + ]) a.len ++;
return a;
} friend BigInt operator - (BigInt a, BigInt b) {
for(int i = ; i <= a.len; ++ i) {
a.v[i] -= b.v[i];
if(a.v[i] < ) {
a.v[i + ] -= ;
a.v[i] += rad;
}
}
while(a.v[a.len] == )a.len --;
return a;
}
void getint(int k) {
while(k) {
v[++ len] = k % ;
k /= ;
}
} void print() {
for(int i = len; i >= ; -- i) {
printf("%d", v[i]);
}
}
}f[], cst; void Input() {
scanf("%d", &n);
} void Solve() {
f[].getint();
f[].getint();
cst.getint();
for(int i = ; i <= n; ++ i) {
f[i] = f[i - ] * - f[i - ] + cst;
}
} void Output() {
f[n].print();
} int main() {
Input();
Solve();
Output(); return ;
}
BZOJ 1002
题目3: SPOJ 104 HighWays
题目大意:
给一张图,求其生成树的个数。
算法讨论:裸上基尔霍夫。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; typedef long long ll;
const int N = ; ll ans;
int n, m;
ll degree[N][N], G[N][N], self[N][N]; ll det(ll a[N][N]) {
ll res = ; for(int i = ; i < n; ++ i) {
for(int j = i + ; j < n; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i]; for(int k = i; k < n; ++ k)
a[i][k] = (a[i][k] - a[j][k] * t);
for(int k = i; k < n; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = 1LL * res * a[i][i];
}
return res;
} void Input() {
int x, y; memset(self, , sizeof self);
memset(degree, , sizeof degree); scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++ i) {
scanf("%d%d", &x, &y);
degree[x][y] ++;
degree[y][x] ++;
self[x][x] ++; self[y][y] ++;
}
for(int i = ; i <= n; ++ i) {
for(int j = ; j <= n; ++ j) {
G[i][j] = self[i][j] - degree[i][j];
}
}
} void Solve() {
ans = det(G);
} void Output() {
printf("%lld\n", ans);
} int main() {
int t; scanf("%d", &t); while(t --) {
Input();
Solve();
Output();
} return ;
}
SPOJ 104
题目4: BZOJ 4031 [HEOI 2015] 小Z的房间
题目大意:并没有搞懂。只是抄的。河北的题还真是够呛。(PS:我是河北的)
算法讨论:裸上Matrix-Tree定理吧。
#include <bits/stdc++.h> using namespace std; const int N = ;
const int mod = 1e9;
typedef long long ll; int n, m, cnt;
int p[N][N]; ll a[N * N][N * N];
int dx[]={, , , -};
int dy[]={, -, , };
char maze[N][N]; ll det() {
ll res = ; for(int i = ; i < cnt; ++ i)
for(int j = ; j < cnt; ++ j)
a[i][j] = (a[i][j] + mod) % mod;
for(int i = ; i < cnt; ++ i) {
for(int j = i + ; j < cnt; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i]; for(int k = i; k < cnt; ++ k)
a[i][k] = (a[i][k] - a[j][k] * t % mod + mod) % mod;
for(int k = i; k < cnt; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = 1LL * res * a[i][i] % mod;
}
return (res + mod) % mod;
} int main() {
scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++ i) {
scanf("%s", maze[i] + );
}
for(int i = ; i <= n; ++ i)
for(int j = ; j <= m; ++ j)
if(maze[i][j] == '.')
p[i][j] = ++ cnt;
for(int i = ; i <= n; ++ i) {
for(int j = ; j <= m; ++ j) {
if(maze[i][j] != '.') continue;
for(int k = ; k < ; ++ k) {
int nx = dx[k] + i, ny = dy[k] + j; if(nx < || ny < || nx > n || ny > m || maze[nx][ny] != '.') continue;
int u = p[i][j], v = p[nx][ny]; a[u][u] ++; a[u][v] --;
}
}
}
printf("%lld\n", det());
return ;
}
BZOJ 4031
题目5: Uva 10766
题目大意:
求一个有根树的生成树的数量。
算法讨论:
其实这个有根和无根是一样的。直接做就行。
#include <bits/stdc++.h> using namespace std; typedef long long ll;
const int N = ; int n, m, kk;
bool lk[N][N];
ll a[N][N]; ll det() {
ll res = ; for(int i = ; i < n; ++ i) {
for(int j = i + ; j < n; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i]; for(int k = i; k < n; ++ k)
a[i][k] = a[i][k] - a[j][k] * t;
for(int k = i; k < n; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = res * a[i][i];
} return abs(res);
} int main() {
int u, v; while(~scanf("%d%d%d", &n, &m, &kk)) {
memset(lk, false, sizeof lk);
memset(a, , sizeof a);
for(int i = ; i <= m; ++ i) {
scanf("%d%d", &u, &v);
lk[u][v] = lk[v][u] = true;
}
for(int i = ; i <= n; ++ i) {
int cnt = ; for(int j = ; j <= n; ++ j) {
if(i != j && !lk[i][j]) {
a[i][j] = -;
++ cnt;
}
}
a[i][i] = cnt;
}
printf("%lld\n", det());
} return ;
}
Uva 10766
题目6: BZOJ1016 && JSOI2008最小生成树计数
题目大意:
求一个图的最小生成树的个数。
算法讨论:
将边权从小到大SORT。然后对于相同边权的做一次处理进行缩点。如果缩点后出现多个联通块,有两种方法:对每个联通块做Matrix-Tree,然后相乘,或者在两个联通块加一个桥,这样方案数不会受影响。
坑点就是最后如果有形不成树的情况。
代码:
#include <cstdlib>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std;
const int N = + ;
const int M = + ;
const int mod = ;
typedef long long ll; int n, m, tim, cnt;
ll A[N][N], ans = ;
int fa[N], lab[N], repos[N], f2[N]; struct Edge {
int u, v, d;
bool operator < (const Edge &k) const {
return d < k.d;
}
}e[M];
vector <Edge> p[N]; void Init() {
scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++ i) {
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].d);
}
} ll Det(ll a[N][N], int ns) {
ll res = ;
for(int i = ; i < ns; ++ i) {
for(int j = i + ; j < ns; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i];
for(int k = i; k < ns; ++ k)
a[i][k] = (a[i][k] - a[j][k] * t);
for(int k = i; k < ns; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = res * a[i][i];
}
return res;
} int find(int *f, int x) {
return f[x] == x ? x : (f[x] = find(f, f[x]));
} void Work(vector <Edge> &v) {
vector <Edge> :: iterator it;
int poi = ;
++ tim;
for(it = v.begin(); it != v.end(); ++ it) {
if(lab[fa[(*it).u]] != tim) {
lab[fa[(*it).u]] = tim;
repos[fa[(*it).u]] = ++ poi;
}
if(lab[fa[(*it).v]] != tim) {
lab[fa[(*it).v]] = tim;
repos[fa[(*it).v]] = ++ poi;
}
}
for(int i = ; i <= poi; ++ i)
for(int j = ; j <= poi; ++ j)
A[i][j] = ;
for(it = v.begin(); it != v.end(); ++ it) {
-- A[repos[fa[(*it).u]]][repos[fa[(*it).v]]];
-- A[repos[fa[(*it).v]]][repos[fa[(*it).u]]];
++ A[repos[fa[(*it).u]]][repos[fa[(*it).u]]];
++ A[repos[fa[(*it).v]]][repos[fa[(*it).v]]];
}
ans = ans * Det(A, poi) % mod;
} void Calc(int l, int r) {
for(int i = l; i <= r; ++ i) {
f2[fa[e[i].u]] = fa[e[i].u];
f2[fa[e[i].v]] = fa[e[i].v];
p[fa[e[i].u]].clear();
p[fa[e[i].v]].clear();
}
for(int i = l; i <= r; ++ i) {
f2[find(f2, fa[e[i].u])] = find(f2, fa[e[i].v]);
}
for(int i = l; i <= r; ++ i) {
if(fa[e[i].u] != fa[e[i].v]) {
p[find(f2, fa[e[i].u])].push_back(e[i]);
}
}
for(int i = l; i <= r; ++ i) {
if(!p[fa[e[i].u]].empty()) {
Work(p[fa[e[i].u]]), p[fa[e[i].u]].clear();
}
if(!p[fa[e[i].v]].empty()) {
Work(p[fa[e[i].v]]), p[fa[e[i].v]].clear();
}
}
} void Solve() {
sort(e + , e + m + );
cnt = n;
for(int i = ; i <= n; ++ i) fa[i] = i;
for(int i = ; i <= m && cnt > ;) {
int j = i;
for(; e[j].d == e[i].d && j <= m; ++ j) {
find(fa, e[j].u); find(fa, e[j].v);
}
Calc(i, j - );
for(int k = i; k < j; ++ k) {
int fx = find(fa, e[k].u), fy = find(fa, e[k].v);
if(fx != fy) {
fa[fx] = fy;
cnt --;
}
}
i = j;
}
if(cnt != ) ans = ;
printf("%lld\n", ans % mod);
} #define stone_eee
int main() {
#ifndef stone_
freopen("mst.in", "r", stdin);
freopen("mst.out", "w", stdout);
#endif Init();
Solve(); #ifndef stone_
fclose(stdin); fclose(stdout);
#endif
return ;
}
1016
基尔霍夫矩阵题目泛做(AD第二轮)的更多相关文章
- BZOJ 1002: [FJOI2007]轮状病毒【生成树的计数与基尔霍夫矩阵简单讲解+高精度】
1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 5577 Solved: 3031[Submit][Statu ...
- 【BZOJ】1002:轮状病毒(基尔霍夫矩阵【附公式推导】或打表)
Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图 ...
- 无向图生成树计数 基尔霍夫矩阵 SPOJ Highways
基尔霍夫矩阵 https://blog.csdn.net/w4149/article/details/77387045 https://blog.csdn.net/qq_29963431/articl ...
- bzoj1002: [FJOI2007]轮状病毒(基尔霍夫矩阵)
1002: [FJOI2007]轮状病毒 题目:传送门 题解: 决定开始板刷的第一题... 看到这题的时候想:这不就是求有多少种最小生成树的方式吗? 不会啊!!!%题解... 什么鬼?基尔霍夫矩阵?? ...
- bzoj 1002 [FJOI2007]轮状病毒 高精度&&找规律&&基尔霍夫矩阵
1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2234 Solved: 1227[Submit][Statu ...
- BZOJ1002 FJOI2007 轮状病毒 【基尔霍夫矩阵+高精度】
BZOJ1002 FJOI2007 轮状病毒 Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原 ...
- BZOJ 4031 HEOI2015 小Z的房间 基尔霍夫矩阵+行列式+高斯消元 (附带行列式小结)
原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4031 Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可 ...
- bzoj 1002 找规律(基尔霍夫矩阵)
网上说的是什么基尔霍夫矩阵,没学过这个,打个表找下规律,发现 w[i]=3*w[i-1]-w[i-2]+2; 然后写个高精直接递推就行了 //By BLADEVIL var n :longint; a ...
- [bzoj1002] [FJOI2007]轮状病毒轮状病毒(基尔霍夫矩阵)
Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子 和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下 ...
随机推荐
- XP 安装
提供一下裝系統的詳細步驟,盡量詳細到每一步都有,希望能對樓主有所幫助,不盡之處還請樓主不吝指出!謝謝 装XP的步骤如下: 开机时,按del键, 进入bios界面,一般选左侧第二项,(Advanced ...
- JS/CSS/IMG加载顺序关系之DOMContentLoaded事件
DOMContentLoaded介绍 DOMContentLoaded事件的触发条件是: 将会在“所有的DOM全部加载完毕并且JS加载执行后触发”. 但如果“js是通过动态加载进来的话,是不会影响到D ...
- python中的super
super用于类的继承.用super()代替父类名 (一)通过类名调用父类中的方法 (二 ...
- iOS学习之导航条NavigationControl的一些属性设置
/** * 配置公共的属性,该属性作用于所有的导航条界面; */ - (void)configureConmmonPropety { //1.设置导航条的颜色 self.navigationContr ...
- 【转】对ARM堆栈的理解
对ARM堆栈的理解 堆栈严格来说应该叫做栈,栈(Stack)是限定仅在一端进行插入或删除操作的线性表.因此,对栈来说,可以进行插入或删除操作的一端端称为栈顶(top),相应地,另一端称为栈底(bott ...
- JAVA_build_ant_mapper
ant里面mapper的详细用法 ant里面mapper标签是和fileset配合使用的,目的就是把fileset取出的文件名转成指定的样式.其实看懂官方文档后,感觉真心没啥好写的.但是还是写一下 ...
- OC高级编程——深入block,如何捕获变量,如何存储在堆上
OC高级编程——深入block,如何捕获变量,如何存储在堆上 首先先看几道block相关的题目 这是一篇比较长的 博文 ,前部分是block的测试题目,中间是block的语法.特性,block讲 ...
- MTKdroidToolsV2.53 MTK安卓提取线刷资料的工具 使用教程
备份的时候需插入1G以上内存卡,并确保机器电量充足. 机器需要root才能备份. 最新版本 支持大部分机型 一键root
- 不知道算不算另类的ASP.NET MVC4 Ajax分页
以往用Ajax来实现无刷新分页,用户一按F5,页数就记不住了,点了一个链接也是同一个问题,再想回退回来,就回到第一页了.上次看到一篇文章,说到window.location.hash的用途,于是萌生了 ...
- 主题模型-LDA浅析
(一)LDA作用 传统判断两个文档相似性的方法是通过查看两个文档共同出现的单词的多少,如TF-IDF等,这种方法没有考虑到文字背后的语义关联,可能在两个文档共同出现的单词很少甚至没有,但两个文档是相似 ...