官方题解:
402E - Strictly Positive Matrix / 403C - Strictly Positive Matrix
Let's look at the matrix a as a connectivity matrix of some graph with n vertices. Moreover, if aij > 0, then we have directed edge in the graph between nodes (i, j). Otherwise, if aij = 0 that graph does not contains directed edge between pair of nodes (i, j). Let b = ak. What does bij means? bij is the number of paths of length exactly k in our graph from vertex i to vertex j. Let pos is an integer, such thata[pos][pos] > 0. That is, we have a loop in the graph. So, if from the vertex pos achievable all other vertexes and vice versa, from all other vertices reachable vertex pos, then the answer is YES, otherwise the answer is NO. If reachability is missing, it is clear that for anyk akipos = 0. If reachability there, we will be able to reach self-loop, use self-loop "to twist", and after that we will go to some another vertex.
大概题意:给定一个矩阵A(n*n的),对角线为1,其它位置为0或1.B= A^k,问是否存在某个k使得B中每个元素都为1.
矩阵阶乘和图上路径计数问题的转换:
(矩阵的元素为A[i][j] = 1代表图上点i可达点j,特殊的A[i][i] = 1。表示点i存在自环。)
转化为图的问题。对应的图为:
n个点,A[i][j] = 1,则i和j之间连边,否者不连。
则B = A^k,B[i][j]代表的含义为,从i到j的路径长度为k的路径的个数。
由于本题中对角线为1,即任意点存在子环,则如果存在从i到j的长度为k 的路径,则存在从i到j长度为k+1,k+2.。。的路径。
所以只需判断可到达即可,即任一点可到达其他所有点。可用floyd,判强连通为1,或判任意点都和同一点在一个环上即可(必要条件)。
本题是判断是否存在,则用必要条件去判断即可
floyd的解法和判任意点都和同一点在一个环上的解法:
int n;
bitset<2010>f[2010];
int main ()
{
RI(n);
REP(i, n) REP(j, n)
{
int x;
RI(x);
f[i][j] = !!x;
}
REP(k, n) REP(i, n)
if (f[i][k]) f[i] |= f[k];
int fla = 1;
REP(i, n) REP(j, n) if (!f[i][j])
{
fla = 0; break;
}
if (fla) puts("YES");
else puts("NO");
return 0;
}
int n;
bool f[2010][2010];
bool used[2010], rused[2010];
void dfs(int u)
{
used[u] = 1;
REP(i, n) if (f[u][i] && !used[i]) dfs(i);
}
void rdfs(int u)
{
rused[u] = 1;
REP(i, n) if (f[i][u] && !rused[i]) rdfs(i);
}
int main ()
{
RI(n);
REP(i, n) REP(j, n)
{
int x;
RI(x);
f[i][j] = !!x;
}
dfs(0);
rdfs(0);
int fla = 1;
REP(i, n) if (!used[i] || !rused[i])///都为1说明成环
fla = 0; break;
if (fla) puts("YES");
else puts("NO");
return 0;
}
下题是图上路径计数问题转化成矩阵阶乘问题:
ac自动机中求长度为L的特定字符串的个数, AC自动机 其实 就是创建了一个状态的转移图(也是一个图),思想很重要
详见:http://www.cnblogs.com/kuangbin/p/3164106.html
中的
另:fzu一题,Problem 2173 Nostop
竟然可以求最优值,涨了姿势。(从点1到点n的经过k条边,的最短路径值问题)
正确性,还待理解(只要满足结合律???)
ps:本题中不允许在一点停留,所以初始化对角线为INF。这样就没办法建立单位1矩阵,所以在快速幂中,第一个是赋值,之后才是乘法
//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
//OUTPUT
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s)
typedef long long LL;
const LL INF = 1LL * 1e18;
const double eps = 1e-10;
const int maxn = 100010;
const int MOD = 1000000007;
struct Metrix{
LL tab[55][55];
int n;
Metrix(int n)
{
this->n = n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
tab[i][j] = INF;
}
Metrix operator*(Metrix a)
{
Metrix ret(n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int r = 1; r <= n; r++)
ret.tab[i][j] = min(ret.tab[i][j], tab[i][r] + a.tab[r][j]);
return ret;
}
};
int n, T, m, k;
Metrix quick_pow(Metrix a, int k)
{
Metrix ret(n);
int st = 0;
while (k)
{
if (k & 1)
{
if (st) ret = ret * a;
else ret = a;
st = 1;
}
k >>= 1;
a = a * a;
}
return ret;
}
int main ()
{
RI(T);
while (T--)
{
RIII(n, m, k);
Metrix tmp(n);
for (int i = 0; i < m; i++)
{
int x, y;
LL z;
cin >> x >> y >> z;
tmp.tab[x][y] = min(tmp.tab[x][y], z);
}
Metrix ans = quick_pow(tmp, k);
if (ans.tab[1][n] == INF) ans.tab[1][n] = -1;
cout << ans.tab[1][n] << endl;
}
return 0;
}
/***
1
3 2 2
1 2 2
2 3 3
1
5 5 3
1 2 1
2 5 1
1 3 10
3 4 10
4 5 10
*/