2723 Get Luffy Out

問題概要

m枚の扉を順に、なるべく多くの枚数を開けたい。
扉には二つの錠があり、どちらかの錠を開ければ扉は開く。


錠は2*n種類あり、全ての錠にはただ一つの異なる錠が対応している。
錠の鍵を一度使用すると、対応する錠の鍵は消滅して使用不可能になる。

錠の対応関係および、各扉についている錠の番号が与えられるとき、
開けられる扉の最大の枚数を求めよ。


n≦1024,m≦2048を満たす。

解法

k番目までの扉を開けられるかについて考える。
対になっている鍵はどちらか一方しかつかえず、かつk番目までの全ての扉を開けなければならない。これは良く見ると2-SAT問題である。


2-SATは線形時間で解けるので、あとはkを動かして二分探索すればよい。


2-SATの問題解いたの初めてのような気がする……
上位の人の実行速度は1000倍くらい速いので、もしかしたら二分探索要らないのかも?

ソースコード

int n,m,p[3000],ky[3000];

int main(){
	while(scanf("%d%d",&n,&m),n){
	vector<clause> cs;
		rep(i,n){
			int a,b; scanf("%d%d",&a,&b);
			p[a]=VAR(i); p[b]=NOT(VAR(i));
		}
		rep(i,m){
			int a,b; scanf("%d%d",&a,&b);
			cs.pb(mp(p[a],p[b]));
		}
		int lo=1,hi=m+1,mid;
		while(lo+1<hi){
			mid=(lo+hi)/2;
			if(two_satisfiability(mid,n,cs))lo=mid; else hi=mid;
		}
		printf("%d\n",lo);
	}
	return 0;
}