牛客网传送
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format:%lld
链接:https://ac.nowcoder.com/acm/contest/4860/B
来源:牛客网
题目描述
Farmer John’s N cows (1 <= N <= 100), conveniently numbered 1…N, are
standing in a row. Their ordering is described by an array A, where
A(i) is the number of the cow in position i. Farmer John wants to
rearrange them into a different ordering for a group photo, described
by an array B, where B(i) is the number of the cow that should end up
in position i.For example, suppose the cows start out ordered as follows:
A = 5 1 4 2 3
and suppose Farmer John would like them instead to be ordered like
this:B = 2 5 3 1 4
To re-arrange themselves from the “A” ordering to the “B” ordering,
the cows perform a number of “cyclic” shifts. Each of these cyclic
shifts begins with a cow moving to her proper location in the “B”
ordering, displacing another cow, who then moves to her proper
location, displacing another cow, and so on, until eventually a cow
ends up in the position initially occupied by the first cow on the
cycle. For example, in the ordering above, if we start a cycle with
cow 5, then cow 5 would move to position 2, displacing cow 1, who
moves to position 4, displacing cow 2, who moves to position 1, ending
the cycle. The cows keep performing cyclic shifts until every cow
eventually ends up in her proper location in the “B” ordering. Observe
that each cow participates in exactly one cyclic shift, unless she
occupies the same position in the “A” and “B” orderings.Please compute the number of different cyclic shifts, as well as the
length of the longest cyclic shift, as the cows rearrange themselves.
输入描述:
Line 1: The integer N.
Lines 2…1+N: Line i+1 contains the integer A(i).
Lines 2+N…1+2N: Line 1+N+i contains the integer B(i)
输出描述:
- Line 1: Two space-separated integers, the first giving the number of cyclic shifts and the second giving the number cows involved in the
longest such shift. If there are no cyclic shifts, output -1 for the
second number.
示例1
输入
5
5
1
4
2
3
2
5
3
1
4
输出
2 3
题意:
比如样例:通过移动A,将A=B
A 5 1 4 2 3
B 2 5 3 1 4
id 1 2 3 4 5
首先A中5要到1的位置(id=2),然后1移动到2的位置上(id=4),2要移动到5的位置上上(id=1)就是一个环,5->1->2->5,移动次数为3(也就是环的长度),除此之外还有4->3->4,移动次数为2,问将A通过移动转化成B的过程中,最长移动次数(即最长的环)是多少?环的数量是多少?
题解:
(第一二个代码讲述的是我做错的过程,正解在是第三个)
这题是我难以忘记的痛o(╥﹏╥)o
看完这个题第一反应是noip考过的信息传递,所以一开始就用并查集来做,father[A[id]]=B[id](就是id相对于A的父亲节点是B),因为一定能成环,所以就找一共多少个环,并求出最长环的长度
然而。。。。
我调了一阵子也但还是段错误,我换了个oj测评一下,然后就就AC了。。。玄学(可能这个oj数据弱 )
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
int a[10000];
int b[194000];
int father[10003];
bool f[100004];
int maxx=0;
void unionn(int x,int y)
{father[x]=y;
}
int find(int x,int z)
{if(father[x]==x)return 0;//如果这个数在A中与B中位置相同,不需要交换else if(f[x]==1&&z==0)return 0;//如果这个数曾经被查询过else if(f[x]==1&&z!=0)return 1;//如果这个环第一次被查询z++;//z只有0和非0,来表示这个数之前是否被查询过f[x]=1;maxx=max(maxx,z);find(father[x],z);//不断地向后查找5->1->2
}
int main()
{cin>>n;for(int i=1;i<=n;i++){cin>>a[i];}for(int j=1;j<=n;j++){cin>>b[j];unionn(a[j],b[j]);}int tot=0;for(int i=1;i<=n;i++){if(a[i]!=b[i])tot++;}if(tot==0){cout<<0<<" "<<-1;return 0;}int ant=0;for(int i=1;i<=n;i++){if(find(i,0))ant++;}cout<<ant<<" "<<maxx;
}
我痛定思痛,感觉是因为自身递归导致段错误,又改了一个思路,在寻找根节点并压缩路径的时候,顺便用dis来记录路径的长度,然后统计出最长的路径。
结果没段错误,但。。。wa了。。唉
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
int a[10030];
int b[19333];
int father[100333];
bool f[10034];//标记这个点所在的环是否被查询过
int dis[100022];
int maxx=0;
//void unionn(int x,int y)
//{
// father[x]=y;
//}
void init()
{for(int i=1;i<=n;i++){father[i]=i;}
}
int find(int x)
{if(father[x]!=x){int last=father[x];father[x]=find(father[x]);dis[x]+=dis[last];}return father[x];
}
void unionn(int aa,int bb)
{if(aa==bb)return;int x=find(aa);int y=find(bb);if(x!=y){father[x]=y;dis[aa]=dis[bb]+1;}else maxx=max(maxx,dis[aa]+dis[bb]+1);//更新最长边
}
//int find(int x,int z)
//{
// if(father[x]==x)return 0;
// else if(f[x]==1&&z==0)return 0;
// else if(f[x]==1&&z!=0)return 1;
// z++;
// f[x]=1;
// maxx=max(maxx,z);
// find(father[x],z);
//}
int main()
{cin>>n;for(int i=1;i<=n;i++){cin>>a[i];}for(int j=1;j<=n;j++){cin>>b[j];}init();int tot=0;for(int i=1;i<=n;i++){if(a[i]!=b[i])tot++;else f[a[i]]=1;}if(tot==0){cout<<0<<" "<<-1;return 0;}int ant=0;//多少个环for(int i=1;i<=n;i++){unionn(a[i],b[i]);}for(int i=1;i<=n;i++){if(f[father[i]]==0){ant++;f[father[i]]=1;}}cout<<ant<<" "<<maxx;
}
我冷静一会后,重新思考,感觉把题越想越复杂了
样例:
A 5 1 4 2 3
B 2 5 3 1 4
f[]来标记id是否被查询过
我们用fa和fb来记录A和B中数的id位置,然后在union时,通过father[]来让 A中的点对应B的位置相互指向,A中id=1的5指向id=2的1,father[5]=1,依次类推
A ------->5 1 4 2 3
fa------->2 4 5 3 1
B-------->2 5 3 1 4
fb-------->4 1 3 5 2
father—>2 4 5 1 3
在查找时for(i->n),查询该点i后,接着查与这点i相连的点father[i],并用f[]标记,ans记录长度,如果相连的点>2(也就是这个点不是指向自己),统计最长环长,并记录换的数量
#include<bits/stdc++.h>
#define for(n) for(int i=1;i<=n;i++)
using namespace std;
typedef long long ll;
int n;
int a[10030];
int b[19333];
int father[100333];
int fa[10034];
int fb[10034];
int f[100022];
int maxx=0;
int ans;
int id;
int tot=0;
int w=0;
int find()
{for(n){if(f[i]==0){id=i;ans=0;while(f[id]==0){f[id]=1;ans++;id=father[id];}if(ans>1){tot=max(ans,tot);w++;}}}return tot;
}
void init()
{for(n){fa[a[i]]=i; fb[b[i]]=i;}
}
void init1()
{for(n){father[fa[a[i]]]=fb[a[i]];} }
//void unionn(int x,int y)
//{
// father[x]=y;
//}
//void unionn(int aa,int bb)
//{
// if(aa==bb)return;
// int x=find(aa);
// int y=find(bb);
// if(x!=y)
// {
// father[x]=y;
// dis[aa]=dis[bb]+1;
// }
// else maxx=max(maxx,dis[aa]+dis[bb]+1);
//}
// for(int i=1;i<=n;i++)
// {
// if(a[i]!=b[i])tot++;
// else f[a[i]]=1;
// }
// if(tot==0)
// {
// cout<<0<<" "<<-1;
// return 0;
// }
// int ant=0;
// for(int i=1;i<=n;i++)
// {
//
// unionn(a[i],b[i]);
// }
// for(int i=1;i<=n;i++)
// {
// if(f[father[i]]==0)
// {
// ant++;
// f[father[i]]=1;
// }
// }
// cout<<ant<<" "<<maxx;
int main()
{cin>>n;for(n)cin>>a[i];for(n)cin>>b[i];init();init1();if(find()==0)cout<<0<<" "<<-1;else cout<<w<<" "<<tot;}
终于做出来了。。。我太菜了o(╥﹏╥)o