传递闭包/并查集~
首先说说我的做法:传递闭包。
直接用floyd传递闭包,如果f[i][k]和f[k+1][j]以及f[i][j]都已知,那么判断f[i][j]是否等于f[i][k]+f[k+1][j]即可。
<span style="font-size:18px;">#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <cmath> #define inf 0x3f3f3f3f using namespace std; int a[105][105],n,m; void read(int &tmp) { tmp=0; char ch=getchar(); int fu=1; for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') fu=-1; for (;ch>='0'&&ch<='9';ch=getchar()) tmp=tmp*10+ch-'0'; tmp*=fu; } int main() { int T; read(T); while (T--) { read(n),read(m); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) a[i][j]=inf; int ok=1; for (int i=1;i<=m;i++) { int s,t,v; read(s),read(t),read(v); if (a[s][t]==inf) a[s][t]=v; else if (a[s][t]!=v) { ok=0; break; } } if (!ok) { puts("false"); continue; } for (int k=1;k<n;k++) for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { if (a[i][k]!=inf&&a[k+1][j]!=inf) { if (a[i][j]==inf) a[i][j]=a[i][k]+a[k+1][j]; else if (a[i][j]!=a[i][k]+a[k+1][j]) { ok=0; break; } } } if (!ok) puts("false"); else puts("true"); } return 0; } </span>
搜题解的做法是并查集!感觉并查集非常非常强大!
带权值的并查集:
在路径压缩的时候,不仅要把f[]更新,还要同时更新权值数组。
如果已知i-j的权值,如果i,j不在同一个并查集中,那么把i和j加入到同一个并查集中;
如果i和j在同一个并查集中,表示i-j的权值已知,那么现在就可以判断了。
为了快速得到i-j的权值,需要记录dis[i]表示i到f[i]的权值和,在路径压缩的时候,需要同时更新dis[i]的值。
int tmp=Getfather(f[i]);
dis[i]+=dis[f[i]];
return f[i]=tmp;
(一定要注意顺序)
感悟:
1.对于floyd,一定要注意把k写在最外层,对于此题k写在最里层也可以过(但是耗时长);但是对于普遍的情况,k写在里面会有bug
2.并查集维护前缀和很神奇~