zoukankan      html  css  js  c++  java
  • [洛谷P5049][洛谷P5022][题解]旅行

    0.一些东西

    原题
    数据加强版
    加强版代码参考你谷题解
    终于调过了(又是一如既往的申必错误)
    €€£ NOI plus石锤了

    1.题解

    原题的数据允许我们(O(n^2))暴力断边,但是加强版的数据达到了(nlog n)级别,我们必须在断边这一环节寻求更好的解法。
    考虑我们进入环后在何处回溯(根据继续走环走到的点分类):
    qwq
    (设当前已经从(b)走到(c)
    1.编号最小((d<e,f)):显然可以直接继续走;
    2.编号非最大/最小((e<d<f)):按大小顺序走完支链再来;
    3.编号最大((d>e,f)):需要分两种情况讨论,
    ①出边就是最大的((d>b)),此时回溯更优;
    ②回溯后的比出边大((b>d)),只能硬着头皮走下去。
    所以说在走的时候需要记录一下最大点,这时候把边按照终点排序会很有帮助。

    2.细节

    1.只能回溯一次,注意标记(代码中back);
    2.注意一些功能的实现(如找环、排边等等)。

    3.代码

    (附注释)
    (缺省源在置顶博客)

    #define N 500010
    int n,m,ans[N],tot,back,mx,isring;
    int vis[N],rin[N],fa[N];
    struct Input {
    	int frm,to;
    	Input(int _u=0,int _v=0){
    		frm=_u,to=_v;
    	}
    }ipt[N<<1];
    bool operator < (Input a,Input b){
    	return a.to>b.to;
    }
    struct Edge {
    	int to,nxt;
    }e[N<<1];
    int head[N],cnt;
    inline void ade(int u,int v){
    	e[++cnt].to=v;
    	e[cnt].nxt=head[u];
    	head[u]=cnt;
    }
    void DFS1(int now){//处理树的情况 
    	ans[++tot]=now,vis[now]=1;
    	for(rg int i=head[now];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(!vis[v])DFS1(v);
    	}
    }
    void DFS_Ring(int now,int ff){//找环 
    	if(isring)return;//找到环的标记 
    	if(!fa[now])fa[now]=ff;
    	else if(fa[now]!=ff){//找到环了 
    		while(ff!=now){//不断回溯回去 
    			rin[ff]=1;
    			ff=fa[ff];
    		}
    		rin[now]=isring=1;
    		return;
    	}
    	for(rg int i=head[now];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v!=ff)DFS_Ring(v,now);
    	}
    }
    void DFS2(int now){//处理基环树的情况 
    //	cout<<"search "<<now<<endl;
    	ans[++tot]=now,vis[now]=1;
    	if(rin[now]){//在环上,特殊处理 
    		int frog=0;//是否需要回溯(第三种情况) 
    		for(rg int i=head[now];i;i=e[i].nxt){
    			if(back)break;//不需要回溯了 
    			int v=e[i].to;
    			if(!vis[v]){
    				if(rin[v]){//终点在环上的出边 
    					i=e[i].nxt;
    					while(vis[e[i].to])i=e[i].nxt;//不断跳访问过的 
    					if(i)mx=e[i].to;//不是最大的出边 
    					else if(v>mx)frog=back=1;//是最大的,回溯
    					//此处运用到了排序后边的顺序 
    					break;
    				}
    			}
    		}
    		for(rg int i=head[now];i;i=e[i].nxt){
    			int v=e[i].to;
    //			printf("vis[%d]=%d,rin[%d]=%d,frog=%d
    ",v,vis[v],v,rin[v],frog);
    			if(!vis[v]){
    				if(!rin[v]||!frog)DFS2(v);//不需要回溯(注意||的使用) 
    			}
    		}
    	}else {//不在环上的正常走即可 
    		for(rg int i=head[now];i;i=e[i].nxt){
    			int v=e[i].to;
    			if(!vis[v])DFS2(v);
    		}
    	}
    }
    int main(){
    	Read(n),Read(m);
    	for(rg int i=1;i<=m;i++){
    		int u,v;
    		Read(u),Read(v);
    		ipt[i]=Input(u,v),ipt[i+m]=Input(v,u);//先存一下 
    	}
    	sort(ipt+1,ipt+1+2*m);
    	for(rg int i=1;i<=2*m;i++)ade(ipt[i].frm,ipt[i].to);//排序后加边 
    	if(m==n-1){
    		DFS1(1);
    		for(rg int i=1;i<=n;i++)cout<<ans[i]<<" ";
    	}else {
    		DFS_Ring(1,1);/*
    		for(rg int i=1;i<=n;i++){
    			printf("rin[%d]=%d
    ",i,rin[i]);
    		}*/
    		DFS2(1);
    		for(rg int i=1;i<=n;i++)cout<<ans[i]<<" ";
    	}
    	return 0;
    }
    

    4.完结撒花~

    继续咕咕咕

  • 相关阅读:
    Redis02——Redis单节点安装
    Redis01——Redis产生背景
    验证元素的唯一性(二重循环法和快排优化)
    线性同余法的伪随机数
    转载(为啥要对10000007取模)
    (算法专题)使用常微分方程将递归转换为非递归
    算法设计与分析——习题一
    PAT Basic 1030 完美数列 (25 分)
    禁止yum update 自动更新系统内核
    Redis AOF 持久化方式
  • 原文地址:https://www.cnblogs.com/juruoajh/p/13692499.html
Copyright © 2011-2022 走看看