zoukankan      html  css  js  c++  java
  • CF36E Two Paths

    XXXV.CF36E Two Paths

    为什么这题会被归到数据结构博客里呢?因为我的代码使用了大剂量的 STL

    我吹爆 list 有没有!再也不手写链表了(并不),但是在欧拉路问题上真的贼好用!

    首先,覆盖所有边恰一次,妥妥的欧拉路模型。

    然后就先考虑如何判无解了。怎样无解呢?

    1. 有少于 \(2\) 条边。(如果不是样例给了,大概很难注意到……)

    2. 有超过 \(2\) 个连通块。

    3. 仅有一个连通块,且连通块中奇点数大于 \(4\)

    4. 有两个连通块,且其中某一个块中奇点数大于 \(2\)

    那么,是否所有条件都满足,就一定有解呢?

    是的。

    假如从欧拉路的方向考虑,就会非常麻烦,因为你找出的欧拉路删去后可能使得这张图分成许多不连通的图。

    因此,这里有一个很好的思路:在两个奇点间连边,这样就会转换为欧拉回路,然后在欧拉回路上断去新加的边就行了。

    具体而言,对于两个连通块的情形,显然上述结论正确,因为每个连通块都必然符合条件。

    然后,对于仅有一个连通块的情形,其中可能有 \(0\) 个,\(2\) 个或是 \(4\) 个奇点。

    \(0\) 个奇点就搜出回路然后随便砍两刀断环成链即可。

    \(2\) 个奇点就在额外连的那条边处砍一刀,然后再随便砍一刀就行。

    \(4\) 个奇点这两刀必须砍在额外的两条边的位置。这形成的两条链必然非空,因为这两条新边必然无公共端点,即其在欧拉环上必然不相邻。

    时间复杂度 \(O(m)\)

    致死量 STL 的代码:

    #include<bits/stdc++.h>
    using namespace std;
    int m,n,X[10010],Y[10010],dsu[20010],lim,id[20010];
    bool deg[20010],used[10010];
    vector<int>v,u[20010],w[20010];
    int find(int x){return dsu[x]==x?x:dsu[x]=find(dsu[x]);}
    void merge(int x,int y){
    	x=find(x),y=find(y);
    	if(x==y)return;
    	dsu[y]=x;
    }
    #define lst list<int>::iterator
    list<int>ls;
    void dfs(lst pos,int x){
    	while(true){
    		while(!w[x].empty()&&used[w[x].back()])w[x].pop_back();
    		if(w[x].empty())return;
    		int i=w[x].back(),y=X[i]^Y[i]^x;w[x].pop_back(),used[i]=true;
    		dfs(ls.insert(pos,i),y);
    	}
    }
    vector<int>s[3];
    int main(){
    	freopen("input.txt","r",stdin);
    	freopen("output.txt","w",stdout);
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)scanf("%d%d",&X[i],&Y[i]),v.push_back(X[i]),v.push_back(Y[i]);
    	if(m==1){puts("-1");return 0;}
    	sort(v.begin(),v.end()),v.resize(n=unique(v.begin(),v.end())-v.begin());
    	for(int i=1;i<=n;i++)dsu[i]=i;
    	for(int i=1;i<=m;i++)merge(X[i]=lower_bound(v.begin(),v.end(),X[i])-v.begin()+1,Y[i]=lower_bound(v.begin(),v.end(),Y[i])-v.begin()+1),deg[X[i]]^=1,deg[Y[i]]^=1;
    //	for(int i=1;i<=m;i++)printf("%d %d\n",X[i],Y[i]);
    //	for(int i=1;i<=n;i++)printf("(%d,%d)",find(i),deg[i]);puts("");
    	for(int i=1;i<=n;i++)if(dsu[i]==i)id[i]=++lim;
    	for(int i=1;i<=n;i++)u[id[find(i)]].push_back(i);
    	if(lim>=3){puts("-1");return 0;}
    	for(int i=1;i<=m;i++)w[X[i]].push_back(i),w[Y[i]].push_back(i);
    	if(lim==1){
    		vector<int>sp;
    		for(auto i:u[1])if(deg[i])sp.push_back(i);
    		if(sp.size()>4){puts("-1");return 0;}
    		for(int i=0;i<sp.size();i+=2){
    			int eid=m+i/2+1;
    			X[eid]=sp[i],Y[eid]=sp[i+1],w[sp[i]].push_back(eid),w[sp[i+1]].push_back(eid);
    		}
    		dfs(ls.begin(),u[1].back());
    //		printf("%d\n",sp.size());
    		if(sp.empty()){
    			s[1].push_back(ls.front()),ls.pop_front();
    			for(auto i:ls)s[2].push_back(i);
    		}
    		if(sp.size()==2){
    			while(ls.front()<=m)ls.push_back(ls.front()),ls.pop_front();
    			ls.pop_front();
    			s[1].push_back(ls.front()),ls.pop_front();
    			while(!ls.empty())s[2].push_back(ls.front()),ls.pop_front();
    		}
    		if(sp.size()==4){
    			while(ls.front()<=m)ls.push_back(ls.front()),ls.pop_front();
    			ls.pop_front();
    			while(ls.front()<=m)s[1].push_back(ls.front()),ls.pop_front();
    			ls.pop_front();
    			while(!ls.empty())s[2].push_back(ls.front()),ls.pop_front();
    		}
    	}
    	if(lim==2){
    		for(int i=1;i<=2;i++){
    			ls.clear();
    			vector<int>sp;
    			for(auto j:u[i])if(deg[j])sp.push_back(j);
    			if(sp.size()>2){puts("-1");return 0;}
    			if(!sp.empty())X[m+1]=sp[0],Y[m+1]=sp[1],w[sp[0]].push_back(m+1),w[sp[1]].push_back(m+1),used[m+1]=false;
    			dfs(ls.begin(),u[i].back());
    			if(!sp.empty()){while(ls.front()<=m)ls.push_back(ls.front()),ls.pop_front();ls.pop_front();}
    			while(!ls.empty())s[i].push_back(ls.front()),ls.pop_front();
    		}
    	}
    	for(int i=1;i<=2;i++){
    		printf("%d\n",s[i].size());
    		for(auto j:s[i])printf("%d ",j);puts("");
    	}
    	return 0;
    }
    

  • 相关阅读:
    本地坐标转世界坐标为什么是 先缩放后旋转再平移
    cocos子节点转父节点坐标 原理浅析(局部坐标转世界坐标同理)
    Github上关于iOS的各种开源项目集合2(强烈建议大家收藏,查看,总有一款你需要)
    Github上关于iOS的各种开源项目集合(强烈建议大家收藏,查看,总有一款你需要)
    Masonry基本语法
    WebStorm 10.0.4注册码
    如何让CCLayer创造的地图,左右滑动不出现黑边
    GitHub 上排名前 100 的 Objective-C 项目简介
    C语言fmod()函数:对浮点数取模(求余)
    查看笔记本最大支持内存
  • 原文地址:https://www.cnblogs.com/Troverld/p/14612734.html
Copyright © 2011-2022 走看看