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;
			}
		}
posted @ 2023-06-06 18:24  Pwtking  阅读(8)  评论(0)    收藏  举报