题意:对一个对焦线元素为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(); } }