poj 3750 约瑟夫环 + 双循环链表

题目链接 点击打开链接

小孩报数问题
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 12011 Accepted: 5513

Description

有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。

Input

第一行输入小孩的人数N(N<=64) 
接下来每行输入一个小孩的名字(人名不超过15个字符) 
最后一行输入W,S (W < N),用逗号","间隔

Output

按人名输出小孩按顺序出列的顺序,每行输出一个人名

Sample Input

5
Xiaoming
Xiaohua
Xiaowang
Zhangsan
Lisi
2,3

Sample Output

Zhangsan
Xiaohua
Xiaoming
Xiaowang
Lisi


分析:循环报数,数据结构中得用到循环链表,由于有删除操作,需要快速找到节点的前驱节点,所以选择双循环链表,由于有固定的移动操作,所以不采用头结点,代码如下:

import java.io.*;
import java.util.*;
import java.util.*;
import java.util.*;
public class Main {
	  public static void main(String []arsgs){
		  Scanner cin = new Scanner(new BufferedInputStream(System.in)) ;
		  PrintWriter cout = new PrintWriter(System.out) ;
		  List<String> answer = new Solve(cin.nextInt() , cin).ssolve() ;
		  for(String name : answer){
			  cout.println(name);
		  }
		  
		  cout.flush() ;
		  cout.close() ;
	  
	  }
}

	  
  class NNode{
	  String name ;
	  NNode next  , pre;
	  NNode(){
		  next = pre = null ;
	  }
  }
	  

  class Solve{
	  
	  NNode head ;
	  int w , s ;
	  
	  public Solve(int  n , Scanner cin ){
		  make(n) ;
		  NNode now = head ; 
		  for(int i =1 ; i<= n ; i++){  //不带头结点,方便计算,不需要处理空链表
			  now.name = cin.next() ;
			  now = now.next ;
			  
		  }
		  String[] p = cin.next().split(",");
		  w = Integer.parseInt(p[0]) ;
		  s = Integer.parseInt(p[1]) ;
	  
      }
	  //建立双循环链表 , 
	  public void make(int n){
		 head  = new NNode() ;
		 NNode now = head ;
		 for(int i =1 ; i< n  ;i++){
			 now.next = new NNode() ;
			 now.next.pre = now ;
			 now = now.next ;
			 
		 }
		 now.next = head ;
		 head.pre = now ;
	  }
	  //移动s步 , 返回移动s步后的节点
	  NNode move(NNode now , int step){
		  for(int i=1 ;i <= step ; i++)
			  now = now.next ;
		  return now ;
	  }
	  //删除节点
	  //由于删除节点p,须找到其前驱节点,如果用单循环链表,则需耗时O(n),原因在于每个节点只有一个指向后继的指针域,
	  //所以用空间换取时间,增加一个存储其前驱的指针域,用双向循环链表数据结构
	  NNode delete(NNode now){ //返回删除节点的下一位节点
		  now.pre.next  = now.next ;
		  now.next.pre = now.pre ;
		  return now.next ;
	  }
	  
	  List<String> ssolve(){
		  List<String> answer = new ArrayList<String>() ;
		  NNode  now = move(head , w -1) ;
		  while(now.next != now){
			  now = move(now , s-1) ;
			  answer.add(now.name) ;
			  now = delete(now) ;
		  }
		  answer.add(now.name) ; //添加最后一个节点
			  return answer ;
      }
  }	 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值