题意:对一个对焦线元素为1、k*k的01矩阵在布尔运算的意义下进行2006次幂运算(k<1000 )。求得到的矩阵里有几个1。
解法:由于是布尔意义下的运算,k次矩阵乘相当于长度为k的路径个数,由于2006>k,因此可以看做求一个图的传递闭包。可以首先强连通分量缩点,记录每个强连通分量中的点数,在缩点后的图G ‘上对每个点进行一次dfs,求出此连通分量能到达多少个点,累加每个强连通得到总共有多少条路径。
import java.io.*;
import java.util.*;
public class Main {
int maxn = 1010, maxm = 10010;
class node {
int be, ne;
node(int be, int ne) {
this.be = be;
this.ne = ne;
}
}
class Tarjan {
int E[] = new int[maxn], n, len;
node buf[] = new node[maxm];
int dfn[] = new int[maxn], low[] = new int[maxn], cnt;
int stack[] = new int[maxn], top;
boolean instack[] = new boolean[maxn];
int id[] = new int[maxn], num[] = new int[maxn], idx;// 1~idx
void init(int n) {
this.n = n;
Arrays.fill(E, -1);
len = 0;
}
void add(int a, int b) {
buf[len] = new node(b, E[a]);
E[a] = len++;
}
void dfs(int a) {
dfn[a] = low[a] = ++cnt;
instack[a] = true;
stack[top++] = a;
int b = -1;
for (int i = E[a]; i != -1; i = buf[i].ne) {
b = buf[i].be;
if (dfn[b] == 0) {
dfs(b);
if (low[b] < low[a])
low[a] = low[b];
} else if (instack[b] && dfn[b] < low[a])
low[a] = dfn[b];
}
if (low[a] == dfn[a]) {
idx++;
do {
b = stack[--top];
instack[b] = false;
id[b] = idx;
num[idx]++;
} while (b != a);
}
}
void solve() {
cnt = idx = top = 0;
Arrays.fill(dfn, 0);
Arrays.fill(low, 0);
Arrays.fill(num, 0);
Arrays.fill(instack, false);
for (int i = 1; i <= n; i++)
if (dfn[i] == 0)
dfs(i);
shrink();
System.out.println(dp.solve());
}
void shrink() {
dp.init(idx);
for (int a = 1; a <= n; a++)
for (int i = E[a]; i != -1; i = buf[i].ne) {
int b = buf[i].be;
if (id[a] != id[b])
dp.add(id[a], id[b]);
}
for (int i = 1; i <= idx; i++)
dp.num[i] = num[i];
}
}
class DP {
int E[] = new int[maxn], n, len;
node buf[] = new node[maxm];
int num[] = new int[maxn], vis[] = new int[maxn],
sum[] = new int[maxn];
void init(int n) {
this.n = n;
Arrays.fill(E, -1);
len = 0;
}
void add(int a, int b) {
buf[len] = new node(b, E[a]);
E[a] = len++;
}
void dfs(int a, int p) {
vis[a] = 1;
for (int i = E[a]; i != -1; i = buf[i].ne) {
int b = buf[i].be;
if (vis[b] == 0) {
dfs(b, p);
sum[p] += num[b];
}
}
}
int solve() {
int res = 0;
Arrays.fill(sum, 0);
for (int i = 1; i <= n; i++) {
Arrays.fill(vis, 0);
dfs(i, i);
}
for(int i=1;i<=n;i++)
res+=num[i]*(num[i]+sum[i]);
return res;
}
}
DP dp = new DP();
Tarjan tj = new Tarjan();
StreamTokenizer in = new StreamTokenizer(new BufferedReader(
new InputStreamReader(System.in)));
int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
int n, m;
void run() throws IOException {
while (in.nextToken() != in.TT_EOF) {
n = (int) in.nval;
m = nextInt();
tj.init(n);
while(m-->0)
tj.add(nextInt()+1, nextInt()+1);
tj.solve();
}
}
public static void main(String[] args) throws IOException {
new Main().run();
}
}