zoukankan      html  css  js  c++  java
  • #2-SAT,Tarjan,前缀优化建边#洛谷 6378 [PA2010]Riddle

    题目

    (n) 个点 (m) 条边的无向图被分成 (k) 个部分。每个部分包含一些点。

    请选择一些关键点,使得每个部分恰有一个关键点,且每条边至少有一个端点是关键点。


    分析

    每条边至少有一个端点是关键点很好做就是(x'->y,y'->x)
    考虑每个部分恰有一个怎么做,不可能暴力建边,
    考虑把前(i)个是否选新开节点,那么就得满足
    (pre_{a_{i-1}}->a_{i}'qquad a_i->pre_{a_{i-1}}')(选择(1sim i-1)就不能选(i),反之亦然)
    (a_i->pre_{a_i}qquad pre_{a_i}'->a_i')(选择(i)就一定选择(1sim i),反之亦然)
    (pre_{a_i}'->pre_{a_{i-1}}'qquad pre_{a_{i-1}}->pre_{a_i})(选择(1sim i-1)就一定选择(1sim i),反之亦然)
    这样就能强制保证每个部分有且仅有一个,套2-SAT模板就行了


    代码

    #include <cstdio>
    #include <cctype>
    #include <stack>
    #define rr register
    using namespace std;
    const int N=4000011; struct node{int y,next;}e[N<<1];
    int dfn[N],low[N],v[N],as[N],col[N],tot,cnt,et,n,m,k; stack<int>stac;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline signed min(int a,int b){return a<b?a:b;}
    inline void add(int x,int y){e[++et]=(node){y,as[x]},as[x]=et;}
    inline signed fal(int x){return x+n;};
    inline signed tru(int x){return x;}
    inline signed sub(int x){return x+n*2;}
    inline void tarjan(int x){
    	dfn[x]=low[x]=++tot,v[x]=1,stac.push(x);
    	for (rr int i=as[x];i;i=e[i].next)
    	if (!dfn[e[i].y]){
    		tarjan(e[i].y);
    		low[x]=min(low[x],low[e[i].y]);
    	}else if (v[e[i].y])
    	    low[x]=min(low[x],dfn[e[i].y]);
    	if (dfn[x]==low[x]){
    		rr int y; ++cnt;
    		do{
    			y=stac.top(),stac.pop();
    			v[y]=0,col[y]=cnt;
    		}while (x^y);
    	}
    }
    signed main(){
    	n=iut(); m=iut(); k=iut();
    	for (rr int i=1;i<=m;++i){
    		rr int x=iut(),y=iut();
    		add(fal(x),tru(y)),add(fal(y),tru(x));
    	}
    	for (rr int i=1,t;i<=k;++i){
    		t=iut();
    		for (rr int j=1;j<=t;++j){
    			rr int x=iut();
    			add(tru(x),tru(sub(j+tot))),
    			add(fal(sub(j+tot)),fal(x));
    			if (j>1){
    				add(tru(sub(j-1+tot)),tru(sub(j+tot))),
    				add(fal(sub(j+tot)),fal(sub(j-1+tot))),
    				add(tru(x),fal(sub(j-1+tot))),
    				add(tru(sub(j-1+tot)),fal(x));
    			}
    		}
    		tot+=t;
    	}
    	tot=0;
    	for (rr int i=1;i<=n*4;++i) if (!dfn[i]) tarjan(i);
    	for (rr int i=1;i<=n;++i)
    	if (col[tru(i)]==col[fal(i)])
    	    return !printf("NIE");
    	for (rr int i=1;i<=n;++i)
    	if (col[tru(sub(i))]==col[fal(sub(i))])
    	    return !printf("NIE");
    	return !printf("TAK");
    } 
    
  • 相关阅读:
    iOS动画之模拟音量振动条
    LeetCode Reverse Linked List
    Android使用BroadCastRecevier广播实现接收短信,并利用Toast弹出显示内容
    Python+Django+SAE系列教程16-----cookie&amp;session
    初识MVC之建项
    【Android 系统开发】使用 Source InSight 阅读 Android 源代码
    ym—— Android网络框架Volley(终极篇)
    俯视数据库系统原理
    hdu 1269 迷宫城堡
    2014年湖北省TI杯大学生电子设计竞赛论文格式
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13928921.html
Copyright © 2011-2022 走看看