【做题记录】[USACO07MAR] Ranking the Cows G
Problem
洛谷P2881
有 \(n\) 个数,给出 \(m\) 个形如 \(a>b\) 的关系,问还要调查多少关系才能确定所有数的大小关系。
Solution
这题应该有两个方法,floyd 和拓扑排序。这里重点讲拓扑排序。
首先要明确一点,如果没有给任何关系,那么我们要做的就是每两个调查一下关系,那么需要调查的总次数就是
那么,如果有一些关系了呢?我们就不需要调查这些关系了,把已知关系的数量减去,就是现在要调查的关系。
那为啥结果不是 \(\frac{n(n-1)}{2}-m\) 呢?因为关系有传递性,也就是说,\(a>b,b>c\) 可以得出 \(a>c\),可以分析出三条关系,但实际给出的只有两条关系。
接下来的问题就是求我们能分析出的关系了。
我们把关系画成一张图,\(u>v\) 就连一条 \(u\) 到 \(v\) 的边,这样,两点可以确定关系就是其中一点能到达另一点。
Floyd做法
众所周知,Floyd 是用来求全源最短路——也就是任意两点的最短路径。那么我们把 Floyd 数组的定义改一下:\(dis_{u,v}=1/0\) 表示 \(u\) 能否到 \(v\)。我们发现原来的松弛仍然适用,适用的原因还是关系有传递性。
于是就可以很快写出代码:
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=f[i][j]|(f[i][k]&f[k][j]);
最后若f[i][j]=true
或f[j][i]=true
则答案 \(-1\)。
先别急!分析一下代码,发现时间复杂度是 \(O(n^3)\) 的,但 \(n \le 1000\),跑不过去。
拓扑排序做法
还是根据关系有传递性这一性质,我们发现,我们可以按照拓扑序去更新能到达这个点的点,只要在找到一条边时把前面点能到达的点都加到后面的点上即可。(听起来可能有点拗口,仔细理解一下?)
关于拓扑排序的可行性,显然不会出现环,因为环意味着 \(a>b,b>c,c>a\),这显然是不可能的。
于是又能写出以下代码:
while(!q.empty())
{
int x=q.front();
for(int i=1;i<=n;i++)
if(g[x][i])//表示x到i有边
{
for(int j=1;j<=n;j++)
if(f[x][j]) f[i][j]=true//f[a][b]=true表示能分析出a>b的关系
if(!--in[i]) q.push(i);
}
}
最后若f[i][j]=true
或f[j][i]=true
则答案 \(-1\)。
如果用链式前向星存图,可以做到 \(O(n(n+m))\),可通过此题。
bitset 优化复杂度
但是但是,我想用 Floyd 怎么办?我拓扑排序想用邻接矩阵存图怎么办?
满足你!
先讲讲 bitset 是个肾么东西。
定义一个 bitset:
bitset<大小>变量名
然后可以把它当一个 bool 数组使用:
bitset<100>a;
a[5]=true;
a[98]=false;
都是可以的。
那它比 bool 数组好在哪里?支持位运算!
我们还可以把 bitset 当成一个数来看,那么它内部的每一个元素都是二进制的一位。
像这样:
bitset<3>a,b;
a[0]=0,a[1]=1,a[2]=1;
b[0]=1,b[1]=0,b[2]=1;
a^=b
然后a
就变成了:
a[0]:1
a[1]:1
a[2]:0
所以 bitset可以做到区间赋值。接下来就要用这个特性优化两个算法。
对 Floyd 的优化
我们只要枚举中转点和终点,然后对于终点,能走到它的,能走到中转点的都能走到它,那么只要把它们合并一下。
思考一下,\(a\) 有则有,\(b\) 有则有,都没有则没有,这对应着什么操作?按位或!
于是可以写出以下代码:
for(int k=1;k<=n;k++)
for(int j=1;j<=n;j++)
if(g[k][j])//要确保它们有边。
f[j]|=f[k];//合并信息
最后求答案只要减去所有的f[i]
即可。
哦对了,a.count()
是询问 bitset 中 \(1\) 的个数。
对拓扑排序的优化
已经有了上面Floyd的经验,那么这也很好想,也把赋值信息改成按位或就行了。
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=1;i<=n;i++)
if(g[x][i])
{
f[i]|=f[x];
if(!--in[i]) q.push(i);
}
}
最后求答案只要减去所有的f[i]
即可。
a.count()
是询问 bitset 中 \(1\) 的个数。
如果你觉得这篇题解帮到了你,就点个赞吧,比心ღ