zoukankan      html  css  js  c++  java
  • GYM102059B Dev, Please Add This!

    说在前面的话

    让我们一起来赞美凉心的出题人吧!

    我被空间限制折腾的死去活来,建议出题人直接爪巴。

    题解

    首先我们需要建图(废话),一种比较巧妙的建图方式是将每一个方格拆点,拆为横向和纵向两个方向的点,然后横向的点跟左右横向的点连,纵向的点和上下纵向的点连,改变方向只有在一个方向上碰壁了才可以,就是自己横向连向自己的纵向或纵向连横向。需要注意的是,上述操作连的所有边都是有向的。

    然后你就得到了一张有向图,你可以跑一个缩点然后把它变成一张 ( ext{DAG}) ,我们现在需要求的就是能否可以从起点出发,走一条路径并且经过所有的星星。

    直接做好像不是很行,但是我们可以发现一个节点只有走与不走两种情况,同时一个星星最多同时属于两个强连通分量,我们可以用 ( ext{2-sat}) 来维护,即星星的两个强连通分量至少选一个,在 ( ext{DAG}) 上没有前后继关系的节点至多选择一个,然后跑一下 ( ext{tarjan}) 就可以了。

    代码

    #pragma GCC optimize("Ofast")
    
    #include<bits/stdc++.h>
    using namespace std;
    const int N=105;
    int n,m,x,y;
    int mp[N*N],id[N*N][2],tot=0;
    int Id(int x,int y){return x*(m+2)+y;}
    struct Edge{int nxt,from,to;}e[N*N];int fir[N*N],cnt_Edge=0;
    void add(int u,int v){e[++cnt_Edge]=(Edge){fir[u],u,v},fir[u]=cnt_Edge;}
    int dfn[N*N],low[N*N],cnt_dfn=0;
    stack<int> s;bool tag[N*N];
    int bel[N*N],cnt_bel=0;
    void tarjan(int u){
    	// printf("%d
    ",u);
    	dfn[u]=low[u]=++cnt_dfn;
    	s.push(u),tag[u]=true;
    	for(int i=fir[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
    		else if(tag[v]) low[u]=min(low[u],dfn[v]);
    	}
    	if(dfn[u]==low[u]){
    		++cnt_bel;
    		while(s.top()!=u)
    		bel[s.top()]=cnt_bel,tag[s.top()]=false,s.pop();
    		bel[s.top()]=cnt_bel,tag[s.top()]=false,s.pop();
    	}
    }
    Edge E[2][N*N];int Fir[2][N*N],Cnt_Edge=0;
    void Add(int u,int v,int tag){
    	E[tag][++Cnt_Edge]=(Edge){Fir[tag][u],u,v},Fir[tag][u]=Cnt_Edge;
    }
    void add_tag(int x){
    	queue<int> q;
    	q.push(x),tag[x]=true;
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=Fir[0][u];i;i=E[0][i].nxt){
    			int v=E[0][i].to;
    			if(!tag[v]) q.push(v),tag[v]=true;
    		}
    		
    	}
    	q.push(x);
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=Fir[1][u];i;i=E[1][i].nxt){
    			int v=E[1][i].to;
    			if(!tag[v]) q.push(v),tag[v]=true;
    		}
    	}
    }
    #define MEMORY 21474836
    struct Two_Sat{
    	Edge e[MEMORY];int fir[N*N],size=0;
    	void add(int u,int v){e[++size]=(Edge){fir[u],u,v},fir[u]=size;}
    	int dfn[N*N],low[N*N],cnt_dfn=0;
    	stack<int> s;bool tag[N*N];
    	int bel[N*N],cnt_bel=0;
    	void tarjan(int u){
    		dfn[u]=low[u]=++cnt_dfn;
    		s.push(u),tag[u]=true;
    		for(int i=fir[u];i;i=e[i].nxt){
    			int v=e[i].to;
    			if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
    			else if(tag[v]) low[u]=min(low[u],dfn[v]);
    		}
    		if(dfn[u]==low[u]){
    			++cnt_bel;
    			while(s.top()!=u)
    			bel[s.top()]=cnt_bel,tag[s.top()]=false,s.pop();
    			bel[s.top()]=cnt_bel,tag[s.top()]=false,s.pop();
    		}
    	}
    }shit;//这一定要建这么多的图吗?我爪巴了。
    int main(){
    	// freopen("data.in","r",stdin);
    	// freopen("jd.out","w",stdout);
    	cin>>n>>m;
    	for(int i=1;i<=n;++i) mp[Id(i,0)]=mp[Id(i,m+1)]=-1;
    	for(int i=1;i<=m;++i) mp[Id(0,i)]=mp[Id(n+1,i)]=-1;
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			char c;do c=getchar();
    			while(c!='#'&&c!='.'&&c!='*'&&c!='O');
    			if(c=='.') mp[Id(i,j)]=0;
    			if(c=='#') mp[Id(i,j)]=-1;
    			if(c=='*') mp[Id(i,j)]=1;
    			if(c=='O') mp[Id(i,j)]=0,x=i,y=j;
    			if(mp[Id(i,j)]>=0){
    				id[Id(i,j)][0]=++tot;//heng
    				id[Id(i,j)][1]=++tot;//shu
    			}
    		}
    	}
    	// printf("------------
    ");
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			if(mp[Id(i,j)]<0) continue;
    			// printf("%d %d %d %d
    ",i,j,id[Id(i,j)][0],id[Id(i,j)][1]);
    			if(mp[Id(i,j-1)]>=0) add(id[Id(i,j)][0],id[Id(i,j-1)][0]);
    			if(mp[Id(i,j+1)]>=0) add(id[Id(i,j)][0],id[Id(i,j+1)][0]);
    			if(mp[Id(i-1,j)]>=0) add(id[Id(i,j)][1],id[Id(i-1,j)][1]);
    			if(mp[Id(i+1,j)]>=0) add(id[Id(i,j)][1],id[Id(i+1,j)][1]);
    			if(mp[Id(i,j-1)]<0||mp[Id(i,j+1)]<0) add(id[Id(i,j)][0],id[Id(i,j)][1]);
    			if(mp[Id(i-1,j)]<0||mp[Id(i+1,j)]<0) add(id[Id(i,j)][1],id[Id(i,j)][0]);
    		}
    	}//有向图
    	// printf("------------
    ");
    	if(!dfn[id[Id(x,y)][0]]) tarjan(id[Id(x,y)][0]);
    	if(!dfn[id[Id(x,y)][1]]) tarjan(id[Id(x,y)][1]);
    	// printf("------------
    ");
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			if(mp[Id(i,j)]<=0) continue;
    			if(!bel[id[Id(i,j)][0]]&&!bel[id[Id(i,j)][1]]){
    				printf("NO
    ");return 0;
    			}
    		}
    	}
    	// printf("------------
    ");
    	for(int i=1;i<=cnt_Edge;++i){
    		if(!bel[e[i].from]||!bel[e[i].to]) continue;
    		if(bel[e[i].from]!=bel[e[i].to]){
    			Add(bel[e[i].from],bel[e[i].to],0);
    			Add(bel[e[i].to],bel[e[i].from],1);
    		}
    	}//DAG
    	for(int i=1;i<=cnt_bel;++i){
    		for(int j=1;j<=cnt_bel;++j) tag[j]=false;
    		add_tag(i);
    		for(int j=1;j<=cnt_bel;++j)
    		if(!tag[j]) shit.add(i+cnt_bel,j);
    	}
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			if(mp[Id(i,j)]<=0) continue;
    			if(!bel[id[Id(i,j)][0]]){
    				shit.add(bel[id[Id(i,j)][1]],bel[id[Id(i,j)][1]]+cnt_bel);
    				continue;
    			}
    			if(!bel[id[Id(i,j)][1]]){
    				shit.add(bel[id[Id(i,j)][0]],bel[id[Id(i,j)][0]]+cnt_bel);
    				continue;
    			}
    			if(bel[id[Id(i,j)][0]]==bel[id[Id(i,j)][1]]){
    				shit.add(bel[id[Id(i,j)][0]],bel[id[Id(i,j)][0]]+cnt_bel);
    				continue;
    			}
    			shit.add(bel[id[Id(i,j)][0]],bel[id[Id(i,j)][1]]+cnt_bel);
    			shit.add(bel[id[Id(i,j)][1]],bel[id[Id(i,j)][0]]+cnt_bel);
    			// printf("%d %d
    ",bel[id[Id(i,j)][1]],bel[id[Id(i,j)][0]]);
    		}
    	}//2-sat
    	// printf("------------
    ");
    	for(int i=1;i<=cnt_bel*2;++i) if(!shit.dfn[i]) shit.tarjan(i);
    	// printf("------------
    ");
    	for(int i=1;i<=cnt_bel;++i){
    		if(shit.bel[i]==shit.bel[i+cnt_bel]){
    			printf("NO
    ");return 0;
    		}
    	}
    	printf("YES
    ");
    	return 0;
    }
    
  • 相关阅读:
    ViewPager部分源码分析二:FragmentManager对Fragment状态的管理完成ViewPager的child添加或移出
    ViewPager部分源码分析一:加载数据
    Android View的scrollTo(),scrollBy(),getScrollX(),getScrollY()
    关于android的单位dp与px
    ListView + PopupWindow实现滑动删除
    Android自学指导
    Ubuntu 14.04 Trusty安装java环境
    Git+VirtalBaox+Vagrant创建Linux虚拟机
    ListView介绍
    Load store and memoryless
  • 原文地址:https://www.cnblogs.com/Point-King/p/14426845.html
Copyright © 2011-2022 走看看