传递闭包/并查集~
首先说说我的做法:传递闭包。
直接用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.并查集维护前缀和很神奇~
原文地址:http://blog.csdn.net/regina8023/article/details/44014627