原题链接:http://codeforces.com/problemset/problem/780/F
原本nc地想要用bfs搜索来枚举状态,不过显然这样会TLE(当时智商掉线了 汗...)。不过也意识到了2^60次方或许可以用来压缩步数但是没有深入地去思考把其他变量也改成二进制压缩的形式,就像2^k求LCA一样用f[ len ][ 0/1 ][ i ][ j ]来表示从点i以0为起始路径的种类,走len步能否到j,这样的时间和空间都是可以接受的。
以上只是我的一点点想法,原题解来自于博客园ljh2000大神:http://www.cnblogs.com/ljh2000-jump/p/6512325.html
顺便存下代码:
#include <bits/stdc++.h>
#define ll long long
#define inf (ll)(1e18)
#define MAXN 520
using namespace std;
bitset<520> f[62][2][MAXN],tmp,g;//强力推荐bitset用来二进制卡常数
ll ans=0;
int n,m;
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
f[0][c][a][b]=1;
}
for (int i=1;i<=60;i++)
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
{
if (f[i-1][0][j][k])
f[i][0][j]|=f[i-1][1][k];
if (f[i-1][1][j][k])
f[i][1][j]|=f[i-1][0][k];
}
for(int i=1;i<=n;i++)
if(f[60][0][1][i])
{
printf("-1");
return 0;
}
int tag=0;
g[1]=1;
ans=0;
for (int len=59;len>=0;len--)
{
tmp=0;
for (int i=1;i<=n;i++)
if (g[i])
tmp|=f[len][tag][i];
if (tmp.count())
{
g=tmp;
ans+=(1ll<<len);
tag^=1;
}
}
if (ans>inf)
puts("-1");
else
printf("%I64d\n",ans);
return 0;
}