NUAA1650解题报告
描述
cc是个超级帅哥,口才又好,rp极高(这句话似乎降rp),又非常的幽默,所以很多mm都跟他关系不错。然而,最关键的是,cc能够很好的调解各各妹妹间的关系。mm之间的关系及其复杂,cc必须严格掌握她们之间的朋友关系,好一起约她们出去,cc要是和不是朋友的两个mm出去玩,后果不堪设想……
cc只掌握着一些mm之间的关系,但是cc比较聪明,他知道a和b是朋友,b和c 是朋友,那么a和c也是朋友。
下面给出m对朋友关系, cc 定了p次约会,每次约会找两个mm,如果这两个mm是朋友,那么不会出乱子,输出‘safe’,要是不是朋友,那么cc必然会挨……,输出‘cc cry’(T_T)。
输入:
第一行为n,m,p。n为mm的数量,cc知道m对朋友关系,有p次约会。
2到n+1 行,每行一个字符串,为第i个mm的名字。{字符串长度 以下m行,每行两个字符串,用空格隔开 ,为有朋友关系的两个mm的名字。
以下p行,每行为两个字符串,用空格隔开,为这p次约会中两个mm的名字。
{保证数据不会出现没有出现过的名字}
输出:
输出P行表示第i次约会的情况,输出‘safe’或者‘cc cry’
样例输入
3 1 1
AAA
BBB
CCC
AAA CCC
AAA BBB
样例输出
cc cry
下面简单地写几句这一题的解题报告,猛一看题目,完全可以用图论解决,思路是图的连通性探索,可以使用宽搜或者深搜,做了简单的复杂度比较后,我使用了宽搜,在月赛中不幸TLE,也就是超时,并且在第二个测试数据上就超时,遂没有信心继续下去,这几天一直在思索这一题的解法。
后来NOJ上有热心朋友提了三个字“并查集 ”,到百度上搜了一下,大概是一个用树和森林处理不相交集合(Disjoint Sets)的合并及查询问题的方法。配合我刚买的《算法导论》一书,将我的思路总结如下:
将每个朋友之间的关系构造成如图所示的一棵树:
描述了6-0,7-0,8-0,1-7,9-7,3-9,5-9之间的朋友关系,如此如果求1-5是否为朋友关系,只需用while循环求出1节点的祖先是否与5节点的祖先相等,如果相等,则1与5为朋友关系,否则,1与5节点无法共存。
使用JAVA写的程序如下:(其中用到了剪枝和路径压缩,所以效率更高)
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int n=cin.nextInt();
int m=cin.nextInt();
int p =cin.nextInt();
ArrayListals=new ArrayList();
Node[] nodes=new Node[n];//森林
for(int i=0;i als.add(cin.next());
nodes[i]=new Node(i);
}//读入姓名
for(int i=0;iint pos1=als.indexOf(cin.next());
int pos2=als.indexOf(cin.next());
int b1=getBoss(pos1,nodes);
int b2=getBoss(pos2,nodes);
if(b1!=b2){
nodes[b2].pre=nodes[b1];
}
}//读入朋友关系,并构建树状关系
for(int i=0;iint pos1=als.indexOf(cin.next());
int pos2=als.indexOf(cin.next());
int b1=getBoss(pos1,nodes);
int b2=getBoss(pos2,nodes);
if(b1!=b2){
System.out.println("cc cry");
}else{
System.out.println("safe");
}
}
}
private static int getBoss(int pos, Node[] nodes) {//求祖先函数
Node t=nodes[nodes[pos].boss]; //路径压缩,直接定位到直系祖先
if(t.pre!=null){ //如果直系祖先的状态需要修改,则循环求出祖先的祖先
while(t.pre!=null){
t=t.pre;
}
nodes[pos].boss=t.boss;
}
return t.boss;
}
public static class Node{
Node pre; //父节点指针
int boss; //直系祖先
Node(int boss){
pre=null;
this.boss=boss;
}
}
描述了6-0,7-0,8-0,1-7,9-7,3-9,5-9之间的朋友关系,如此如果求1-5是否为朋友关系,只需用while循环求出1节点的祖先是否与5节点的祖先相等,如果相等,则1与5为朋友关系,否则,1与5节点无法共存。
使用JAVA写的程序如下:(其中用到了剪枝和路径压缩,所以效率更高)
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int n=cin.nextInt();
int m=cin.nextInt();
int p =cin.nextInt();
ArrayListals=new ArrayList();
Node[] nodes=new Node[n];//森林
for(int i=0;i als.add(cin.next());
nodes[i]=new Node(i);
}//读入姓名
for(int i=0;iint pos1=als.indexOf(cin.next());
int pos2=als.indexOf(cin.next());
int b1=getBoss(pos1,nodes);
int b2=getBoss(pos2,nodes);
if(b1!=b2){
nodes[b2].pre=nodes[b1];
}
}//读入朋友关系,并构建树状关系
for(int i=0;iint pos1=als.indexOf(cin.next());
int pos2=als.indexOf(cin.next());
int b1=getBoss(pos1,nodes);
int b2=getBoss(pos2,nodes);
if(b1!=b2){
System.out.println("cc cry");
}else{
System.out.println("safe");
}
}
}
private static int getBoss(int pos, Node[] nodes) {//求祖先函数
Node t=nodes[nodes[pos].boss]; //路径压缩,直接定位到直系祖先
if(t.pre!=null){ //如果直系祖先的状态需要修改,则循环求出祖先的祖先
while(t.pre!=null){
t=t.pre;
}
nodes[pos].boss=t.boss;
}
return t.boss;
}
public static class Node{
Node pre; //父节点指针
int boss; //直系祖先
Node(int boss){
pre=null;
this.boss=boss;
}
}
浙公网安备 33010602011771号