codeforces 36E Two Paths
2016-12-04 20:07
267 查看
Once archaeologists found m mysterious papers, each of which had a pair of integers written on them. Ancient people were known to like
writing down the indexes of the roads they walked along, as «a b»
or «b a»,
where a, b are the indexes of two different cities joint by the road . It is also known that the mysterious papers are pages
of two travel journals (those days a new journal was written for every new journey).
During one journey the traveler could walk along one and the same road several times in one or several directions but in that case he wrote a new entry for each time in his journal. Besides, the archaeologists think that the direction the traveler took on a
road had no effect upon the entry: the entry that looks like «a b»
could refer to the road from a to b as
well as to the road from b to a.
The archaeologists want to put the pages in the right order and reconstruct the two travel paths but unfortunately, they are bad at programming. That’s where you come in. Go help them!
Input
The first input line contains integer m (1 ≤ m ≤ 10000).
Each of the following m lines describes one paper. Each description consists of two integers a, b (1 ≤ a, b ≤ 10000, a ≠ b).
Output
In the first line output the number L1.
That is the length of the first path, i.e. the amount of papers in its description. In the following line output L1 space-separated
numbers — the indexes of the papers that describe the first path. In the third and fourth lines output similarly the length of the second path L2 and
the path itself. Both paths must contain at least one road, i.e. condition L1 > 0 and L2 > 0 must
be met. The papers are numbered from 1 to m according
to the order of their appearance in the input file. The numbers should be output in the order in which the traveler passed the corresponding roads. If the answer is not unique, output any.
If it’s impossible to find such two paths, output «-1».
Don’t forget that each paper should be used exactly once, i.e L1 + L2 = m.
Examples
input
output
input
output
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
欧拉路+并查集+思路~
简直要被绕晕了……有好多细节要注意……
首先,要分为只有一个联通块,有一个联通块和有两个及以上联通块,判断联通块数用并查集。
最后一种是不行的,直接输出-1。
对于其余两种,要判断每个点的入度是否满足欧拉路条件(没有奇点或有两个奇点),特别的,对于第二种,每个连通块内要分别判断。
然后,如果有两个奇点,从其中一个出发遍历即可。
在第一种情况中,如果有0个或2个起点,则求出总的欧拉路后从任意处截断。
如果有4个起点,任选两个连边后求欧拉路,再在连的边处截断。
#include<cstdio>
int n,m,x,y,totnum,fi[10001],ne[100001],w[100001],cnt,now[3];
int fa[10001],ru[10001],num[10001],tot[10001],id[100001],ans[100001];
bool b[100001],vis[10001];
void add(int u,int v,int idd)
{
w[++cnt]=v;ne[cnt]=fi[u];fi[u]=cnt;id[cnt]=idd;
}
int findfa(int u)
{
return fa[u]==u ? u:fa[u]=findfa(fa[u]);
}
void findd(int u)
{
vis[u]=1;
for(int i=fi[u];i;i=ne[i])
if(!b[i])
{
b[i]=b[i^1]=1;
findd(w[i]);
ans[++ans[0]]=id[i];
}
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&m);cnt=1;
if(m<=1)
{
printf("-1\n");return 0;
}
for(int i=1;i<=10000;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
if(num[x]) x=num[x];
else num[x]=++n,x=n;
if(num[y]) y=num[y];
else num[y]=++n,y=n;
add(x,y,i);add(y,x,i);ru[x]++;ru[y]++;fa[findfa(y)]=findfa(x);
}
now[0]=1;
for(int i=1;i<=n;i++)
{
if(ru[i]&1) tot[++tot[0]]=i;
if(findfa(i)!=findfa(now[0]))
{
if(!now[1]) now[1]=i;
else if(findfa(now[1])!=findfa(i))
{
printf("-1\n");return 0;
}
}
}
if(tot[0]==1 || tot[0]==3 || tot[0]>4)
{
printf("-1\n");
return 0;
}
if(now[1])
{
if(tot[0])
{
int cntt[2]={0};
for(int i=1;i<=n;i++)
if(ru[i]&1) cntt[findfa(i)==findfa(now[1])]++;
if(cntt[1]>2 || cntt[0]>2)
{
printf("-1\n");
return 0;
}
findd(tot[1]);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
ans[0]=0;
if(tot[0]==2)
{
for(int i=1;i<=n;i++)
if(!vis[i])
{
findd(i);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
}
for(int i=2;i<=3;i++)
if(!vis[tot[i]])
{
findd(tot[i]);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
}
findd(1);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
ans[0]=0;
for(int i=2;i<=n;i++)
if(!vis[i])
{
findd(i);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
}
if(!tot[0])
{
findd(1);
int kkz=ans[0]/2;
printf("%d\n",ans[0]-kkz);
for(int i=ans[0];i>=kkz+2;i--) printf("%d ",ans[i]);printf("%d\n",ans[kkz+1]);
printf("%d\n",kkz);
for(int i=kkz;i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
if(tot[0]==2)
{
findd(tot[1]);
int kkz=ans[0]/2;
printf("%d\n",ans[0]-kkz);
for(int i=ans[0];i>=kkz+2;i--) printf("%d ",ans[i]);printf("%d\n",ans[kkz+1]);
printf("%d\n",kkz);
for(int i=kkz;i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
add(tot[1],tot[2],m+1);add(tot[2],tot[1],m+1);
findd(tot[3]);
for(int i=ans[0];i>=1;i--)
if(ans[i]!=m+1) totnum=i;
else break;
totnum--;
printf("%d\n",m-totnum+1);
for(int i=ans[0];i>totnum+1;i--) printf("%d ",ans[i]);printf("%d\n",ans[totnum+1]);
printf("%d\n",totnum-1);
for(int i=totnum-1;i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
writing down the indexes of the roads they walked along, as «a b»
or «b a»,
where a, b are the indexes of two different cities joint by the road . It is also known that the mysterious papers are pages
of two travel journals (those days a new journal was written for every new journey).
During one journey the traveler could walk along one and the same road several times in one or several directions but in that case he wrote a new entry for each time in his journal. Besides, the archaeologists think that the direction the traveler took on a
road had no effect upon the entry: the entry that looks like «a b»
could refer to the road from a to b as
well as to the road from b to a.
The archaeologists want to put the pages in the right order and reconstruct the two travel paths but unfortunately, they are bad at programming. That’s where you come in. Go help them!
Input
The first input line contains integer m (1 ≤ m ≤ 10000).
Each of the following m lines describes one paper. Each description consists of two integers a, b (1 ≤ a, b ≤ 10000, a ≠ b).
Output
In the first line output the number L1.
That is the length of the first path, i.e. the amount of papers in its description. In the following line output L1 space-separated
numbers — the indexes of the papers that describe the first path. In the third and fourth lines output similarly the length of the second path L2 and
the path itself. Both paths must contain at least one road, i.e. condition L1 > 0 and L2 > 0 must
be met. The papers are numbered from 1 to m according
to the order of their appearance in the input file. The numbers should be output in the order in which the traveler passed the corresponding roads. If the answer is not unique, output any.
If it’s impossible to find such two paths, output «-1».
Don’t forget that each paper should be used exactly once, i.e L1 + L2 = m.
Examples
input
2 4 5 4 3
output
1 2 1 1
input
1 1 2
output
-1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
欧拉路+并查集+思路~
简直要被绕晕了……有好多细节要注意……
首先,要分为只有一个联通块,有一个联通块和有两个及以上联通块,判断联通块数用并查集。
最后一种是不行的,直接输出-1。
对于其余两种,要判断每个点的入度是否满足欧拉路条件(没有奇点或有两个奇点),特别的,对于第二种,每个连通块内要分别判断。
然后,如果有两个奇点,从其中一个出发遍历即可。
在第一种情况中,如果有0个或2个起点,则求出总的欧拉路后从任意处截断。
如果有4个起点,任选两个连边后求欧拉路,再在连的边处截断。
#include<cstdio>
int n,m,x,y,totnum,fi[10001],ne[100001],w[100001],cnt,now[3];
int fa[10001],ru[10001],num[10001],tot[10001],id[100001],ans[100001];
bool b[100001],vis[10001];
void add(int u,int v,int idd)
{
w[++cnt]=v;ne[cnt]=fi[u];fi[u]=cnt;id[cnt]=idd;
}
int findfa(int u)
{
return fa[u]==u ? u:fa[u]=findfa(fa[u]);
}
void findd(int u)
{
vis[u]=1;
for(int i=fi[u];i;i=ne[i])
if(!b[i])
{
b[i]=b[i^1]=1;
findd(w[i]);
ans[++ans[0]]=id[i];
}
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&m);cnt=1;
if(m<=1)
{
printf("-1\n");return 0;
}
for(int i=1;i<=10000;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
if(num[x]) x=num[x];
else num[x]=++n,x=n;
if(num[y]) y=num[y];
else num[y]=++n,y=n;
add(x,y,i);add(y,x,i);ru[x]++;ru[y]++;fa[findfa(y)]=findfa(x);
}
now[0]=1;
for(int i=1;i<=n;i++)
{
if(ru[i]&1) tot[++tot[0]]=i;
if(findfa(i)!=findfa(now[0]))
{
if(!now[1]) now[1]=i;
else if(findfa(now[1])!=findfa(i))
{
printf("-1\n");return 0;
}
}
}
if(tot[0]==1 || tot[0]==3 || tot[0]>4)
{
printf("-1\n");
return 0;
}
if(now[1])
{
if(tot[0])
{
int cntt[2]={0};
for(int i=1;i<=n;i++)
if(ru[i]&1) cntt[findfa(i)==findfa(now[1])]++;
if(cntt[1]>2 || cntt[0]>2)
{
printf("-1\n");
return 0;
}
findd(tot[1]);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
ans[0]=0;
if(tot[0]==2)
{
for(int i=1;i<=n;i++)
if(!vis[i])
{
findd(i);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
}
for(int i=2;i<=3;i++)
if(!vis[tot[i]])
{
findd(tot[i]);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
}
findd(1);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
ans[0]=0;
for(int i=2;i<=n;i++)
if(!vis[i])
{
findd(i);
printf("%d\n",ans[0]);
for(int i=ans[0];i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
}
if(!tot[0])
{
findd(1);
int kkz=ans[0]/2;
printf("%d\n",ans[0]-kkz);
for(int i=ans[0];i>=kkz+2;i--) printf("%d ",ans[i]);printf("%d\n",ans[kkz+1]);
printf("%d\n",kkz);
for(int i=kkz;i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
if(tot[0]==2)
{
findd(tot[1]);
int kkz=ans[0]/2;
printf("%d\n",ans[0]-kkz);
for(int i=ans[0];i>=kkz+2;i--) printf("%d ",ans[i]);printf("%d\n",ans[kkz+1]);
printf("%d\n",kkz);
for(int i=kkz;i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
add(tot[1],tot[2],m+1);add(tot[2],tot[1],m+1);
findd(tot[3]);
for(int i=ans[0];i>=1;i--)
if(ans[i]!=m+1) totnum=i;
else break;
totnum--;
printf("%d\n",m-totnum+1);
for(int i=ans[0];i>totnum+1;i--) printf("%d ",ans[i]);printf("%d\n",ans[totnum+1]);
printf("%d\n",totnum-1);
for(int i=totnum-1;i>1;i--) printf("%d ",ans[i]);printf("%d\n",ans[1]);
return 0;
}
相关文章推荐
- 【Codeforces Beta Round #36】Codeforces 36E Two Paths
- Codeforces MemSQL start[c]up Round 1 /325A Square and Rectangles(模拟)
- codeforces 535B-Tavas and SaDDas
- CodeForces - 658A Bear and Reverse Radewoosh (模拟)水
- Codeforces-368B-Sereja and Suffixes
- Codeforces 785D 范德蒙恒等式的变形
- Codeforces - 862B Mahmoud and Ehab and the bipartiteness
- Codeforces 1B Spreadsheet
- Codeforces 191 C Fools and Roads (树链拆分)
- codeforces 645 D Robot Rapping Results Report 【树形dp】
- CodeForces 630A Again Twenty Five!(水题,规律小题)
- CodeForces 414 C.Mashmokh and Reverse Operation(归并排序)
- codeforces 847M Weather Tomorrow
- codeforces 122
- Codeforces 558E A Simple Task(线段树区间更新)
- Codeforces 630E A rectangle
- CodeForces 501A Contest(水题,感觉BUG)
- Codeforces 796C 想法
- Codeforces 859B Lazy Security Guard
- Codeforces 5C Longest Regular Bracket Sequence dp+stack