Astronauts题解
介绍一种 2-sat 的新做法。
考虑在建图时开三倍数组:\([1,n]\) 代表选择 A 任务,\([n+1,2n]\) 代表选择 B 任务,\([2n+1,3n]\) 代表选择 C 任务。
在此基础上分四种情况讨论:
分别设每一对关系中第一个人的年龄为 \(a\),第二个人的年龄为 \(b\),所有人中总年龄和为 \(sum\)。
则分别有:
\(a\times n\ge sum\) 且 \(b\times n<sum\);
\(a\times n< sum\) 且 \(b\times n<sum\);
\(a\times n\ge sum\) 且 \(b\times n\ge sum\);
\(a\times n< sum\) 且 \(b\times n\ge sum\);
对应到代码上如下:
for (ll i=1;i<=m;++i) {
ll a=in(),b=in();
// old[i] 表示下标为 i 的人的年龄
if (old[a]*n>=sum&&old[b]*n<sum) G[a+2*n].push_back(b+n),G[b+2*n].push_back(a);
else if(old[a]*n<sum&&old[b]*n<sum) G[a+n].push_back(b+2*n),G[b+n].push_back(a+2*n),G[a+2*n].push_back(b+n),G[b+2*n].push_back(a+n);
else if (old[a]*n>=sum&&old[b]*n>=sum) G[a].push_back(b+2*n),G[b].push_back(a+2*n),G[b+2*n].push_back(a),G[a+2*n].push_back(b);
else if (old[a]*n<sum&&old[b]*n>=sum) G[a+2*n].push_back(b),G[b+2*n].push_back(a+n);
}
注意:这个地方是将每个人的年龄乘上 \(n\) 来进行比较的,为避免精度问题。
接下来 Tarjan 的时候也是将 \(n\) 遍历到三倍。
最后取值的时候只取这个人能取到的即可,代码如下:
for (ll i=1;i<=n;++i) {
if (old[i]*n<sum) {
if (color[i+n]>color[i+2*n]) cout<<"C"<<endl;
else cout<<"B"<<endl;
}
else {
if (color[i]>color[i+2*n]) cout<<"C"<<endl;
else cout<<"A"<<endl;
}
}

浙公网安备 33010602011771号