题意:
有一个(n)个点(m)条边的无向图,边有两种类型,分别用(0)和(1)标识
因此图中的任意一条路径都对应一个(01)字符串
定义一个无限长的字符串(s):
开始令(s'=0),然后将(s')的反串(ar{s'})拼到后面得到(s' ar{s'}),如此反复最终得到(s)
求从起点出发,在串(s)上走最多能走多少步
分析:
令(arrive(i,t,u))表示从点(u)出发一共走了(2^i)步所能到达的点的集合,其中(t=0)表示在(s)上走,(t=1)表示在串(ar{s})上走
假设在(s)上有个(u o v)长为(2^i)的路径,在(ar s)上有个(v o w)长为(2^i)的路径,那么拼起来在(s)上就有一条(u o w)长为(2^{i+1})的路径
所以(arrive(i+1,t,u)=igcuplimits_{v in arrive(i,t,u)} arrive(i,1-t,v))
再令(go(i, t, u))表示第(i)轮迭代后,从点(u)出发在串(s)或(ar s)上最多走多少步
如果(v in arrive(i,t,u)),那么就可以用(2^i + arrive(i,1-t,v))去更新(go(i+1,t,u)),相当于把两段路拼起来
#include <cstdio>
#include <bitset>
using namespace std;
const int maxn = 500;
const int maxlog = 61;
typedef long long LL;
LL go[maxlog][2][maxn];
bitset<maxn> arrive[maxlog][2][maxn];
void max(LL& a, LL b) { if(b > a) a = b; }
int main()
{
int n, m; scanf("%d%d", &n, &m);
while(m--) {
int u, v, t; scanf("%d%d%d", &u, &v, &t);
u--; v--;
go[0][t][u] = 1;
arrive[0][t][u][v] = 1;
}
for(int i = 0; i + 1 < maxlog; i++) {
for(int t = 0; t < 2; t++) {
for(int u = 0; u < n; u++) {
go[i+1][t][u] = go[i][t][u];
for(int v = 0; v < n; v++) if(arrive[i][t][u][v]) {
arrive[i+1][t][u] |= arrive[i][t^1][v];
max(go[i+1][t][u], (1LL << i) + go[i][t^1][v]);
}
}
}
}
const LL limit = 1000000000000000000LL;
LL& ans = go[maxlog - 1][0][0];
if(ans > limit) puts("-1");
else printf("%lld
", ans);
return 0;
}