11/16の課題について


11/16の課題


問題A 解答例(1)

import java.io.*;

class Cards{
    int[] card;
    int n;
    Cards(int n0){
	n=n0;
	card=new int[n];
	for(int i=0;i < n;i++){
	    card[i]=n-i;
	}
    }
    void cut(int p,int c){
	int[] extracted=new int[c];
	for(int i=0;i<=c-1;i++){
	    extracted[i]=card[p-1+i];
	}
	for(int i=0;i<=p-2;i++){
	    card[c+p-2-i]=card[p-2-i];
	}
	for(int i=0;i<=c-1;i++){
	    card[i]=extracted[i];
	}
    }
}

class A{
    public static void main(String[]args) throws IOException{
	BufferedReader d=new BufferedReader(new InputStreamReader(System.in));
	String result="";
	for(;;){
	    String nr=d.readLine();
	    int n=Integer.parseInt(nr.split(" ")[0]);
	    int r=Integer.parseInt(nr.split(" ")[1]);
	    if(n==0&&r==0)
		break;
	    else if((r-1)*(r-50)>0||(n-1)*(n-50)>0)
		throw new IllegalArgumentException("数値が規定の範囲外です");
	    else{
		Cards cards=new Cards(n);
		for(int i=0;i < r;i++){
		    String pc=d.readLine();
		    int p=Integer.parseInt(pc.split(" ")[0]);
		    int c=Integer.parseInt(pc.split(" ")[1]);
		    cards.cut(p,c);
		}
		result=result+cards.card[0]+" ";
	    }
	}
	String[] results=result.split(" ");
	for(int i=0;i < results.length;i++){
	    System.out.println(results[i]);
	}
    }
}

コメント

Cardsクラスを作ってすっきりと書いていますね.以下の点がちょっと気になりました.

問題A 解答例(2)

import java.io.*;   
class A{
    public static void main(String[] args) throws IOException{
	BufferedReader d=new BufferedReader(new InputStreamReader(System.in));
	String an="";
	while(true){
	    String s=d.readLine();
	    String is[]=s.split(" ");
	    int n=Integer.parseInt(is[0]);
	    int r=Integer.parseInt(is[1]);
	    if(n==0&&r==0)break;
	    String card="0102030405060708091011121314151617181920212223242526272829303132333435363738394041424344454647484950";
	    for(int i=0;i < r;i++){
		String t=d.readLine();
		String st[]=t.split(" ");
		int p=Integer.parseInt(st[0]);
		int c=Integer.parseInt(st[1]);
		String card1=card.substring(0,2*(n-c-p+1));
		String card2=card.substring(2*(n-c-p+1),2*(n-p+1));
		String card3=card.substring(2*(n-p+1),2*n);
		card=card1.concat(card3);
		card=card.concat(card2);
	    }
	    String a=card.substring(2*(n-1),2*n);
	    if(a.startsWith("0")) a=a.substring(1);
	    an=an.concat(a+":");
	}
	String ans[]=an.split(":");
	for(int i=0;i < ans.length;i++)System.out.println(ans[i]);
    }
}

コメント

文字列操作ですっきりと書きましたね.文字列の連結は,concatを使わなく ても「+」で書けるので,
 card=card.substring(0,2*(n-c-p+1))+
     card.substring(2*(n-p+1),2*n)+
     card.substring(2*(n-c-p+1),2*(n-p+1));
と書けますね.nが50までなので
String card="0102030405060708091011121314151617181920212223242526272829303132333435363738394041424344454647484950";
と書けましたが,そうでなければ,
  String card="";
  java.text.DecimalFormat form=new java.text.DecimalFormat("00");
  for(int i=1;i <= n;i++)
    card+=form.format(i);
とやってその場で作ることもできます.

問題B 解答例(1)

import java.util.*;
import java.io.*;

class B {

  final static int RED = 0;
  final static int BLACK = 1;
  final static int ME = 2;

  static int[][] map;
  static int[][] visited;
  static int w = 0;
  static int h = 0;

  public static boolean isVisited(int x, int y) {
    if (0 <= x && x < w && 0 <= y && y < h && visited[x][y] == 0 && map[x][y] == BLACK) {
      return false;
    } else {
      return true;
    }
  }

  public static void search(int x, int y) {
    visited[x][y] = 1;
    if (!isVisited(x-1, y  )) search(x-1,   y);
    if (!isVisited(x+1, y  )) search(x+1,   y);
    if (!isVisited(  x, y+1)) search(  x, y+1);
    if (!isVisited(  x, y-1)) search(  x, y-1);
    return;
  }

  public static void main(String args[]) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    for(;;) {

      String s;
      if ((s=br.readLine()) == null) break;
      String wh[] = s.split(" ");
      w = Integer.parseInt(wh[0]);
      h = Integer.parseInt(wh[1]);
      if (w==0 && h==0) break;
      
      map = new int[w][h];
      visited = new int[w][h];
      
      // data input
      int x=0, y=0;
      for(int j=0; j < h; j++) {
        s = br.readLine();
        for(int i=0; i < w; i++) {
          if(s.charAt(i) == '#') {
            map[i][j] = RED;
          } else if (s.charAt(i) == '@') {
            x = i; y=j;
            map[i][j] = ME;
          } else {
            map[i][j] = BLACK;
          }
          visited[i][j] = 0;
        }
      }

      search(x, y);

      int n = 0;
      for(int j=0; j < h; j++)
        for(int i=0; i < w; i++)
          if (visited[i][j] == 1)
            n++;
      System.out.println(n);

    }
    
  }
}

コメント

塗りつぶしの問題です.4近傍を再帰的に呼び出す解法となります. 良く書けていますが,以下のよう点は改良可能です.

問題B 解答例(2)

import java.io.*;

class B{
    public static void main(String[] args)throws IOException{
	BufferedReader d=new BufferedReader(new InputStreamReader(System.in));
	char c;
	String s1;
	for(;;){
	    String is[]=(d.readLine()).split(" ");
	    int W=Integer.parseInt(is[0]);
	    int H=Integer.parseInt(is[1]);
	    if(W>20||H>20||W < 1||H < 1) break;
	    int[][] b=new int[W][H];
	    for(int j=0;j < H;j++){
		s1=d.readLine();
		for(int i=0;i < W;i++) {
		    c=s1.charAt(i);
		    if(c=='@') b[i][j]=1;
		    if(c=='.') b[i][j]=2;
		    if(c=='#') b[i][j]=3;
		}
	    }
	    int count=0;
	    for(;;){
		int lcount=count;
		count=0;
		for(int i=0;i < W;i++){
		    for(int j=0;j < H;j++){
			if(b[i][j]==2){
			    if(i>=1){if(b[i-1][j]==1) b[i][j]=1; }
			    if(i <=W-2){if(b[i+1][j]==1) b[i][j]=1; }
			    if(j>=1){if(b[i][j-1]==1) b[i][j]=1; }
			    if(j <=H-2){if(b[i][j+1]==1) b[i][j]=1; }
			}
		    }
		}
		for(int i=0;i < W;i++){
		    for(int j=0;j < H;j++){
			if(b[i][j]==1) count++;
		    }
		}
		if(lcount==count) break;
	    }
	    System.out.println(count);
	}
    }
}

コメント

再帰で呼び出しをせずに,近傍点への伝播を変化がなくなるまで繰り返すプロ グラムです.効率はさきほどのものよりも良くないのですが,簡潔に書けます. さきほどと同様に,countの計算をb[i][j]を書き換えた時だけやる方法はあります.

問題C 解答例(1)

import java.io.*;
import java.math.*;

class C{
    public static int a,n;
    public static int sub(Bunsu b,int c,int length,int aa){
	int x,y;
	int result=0;
	if(length>=n) return 0;
	b.kiyaku();
	
	if(b.p==1 && length==1) result++;
	for(int i=c;i<=Math.sqrt(a/aa);i++){
	    x=b.p*i-b.q;y=b.q*i;
	    if(x<=0) continue;
	    Bunsu temp=new Bunsu(x,y);
	    temp.kiyaku();
	    if(temp.p==1){
      		if(temp.q>=i && i*temp.q<=a/aa){
		    result++;
		}
		result+=sub(temp,i,length+1,aa*i);
		
	    }
	    else {
		result+=sub(temp,i,length+1,aa*i);
	    }
	}
	return result;
    }
    public static void main(String[] args) throws IOException{
	String input;
	String[] tokens;
	int p,q;
	BufferedReader d=new BufferedReader(new InputStreamReader(System.in));
	
	while(true){
	    input=d.readLine();
	    tokens=input.split(" ");
	    
	    p=Integer.parseInt(tokens[0]);
	    q=Integer.parseInt(tokens[1]);
	    a=Integer.parseInt(tokens[2]);
	    n=Integer.parseInt(tokens[3]);

	    if(p==0 && q==0 && a==0 && n==0){
		break;
	    }
	    
      	    System.out.println(sub(new Bunsu(p,q),1,1,1));
	    //a=200;n=5;
	    // System.out.println(sub(new Bunsu(3,2),2,2,2));
	}
    }
}

class Bunsu{
    public int p,q;
    Bunsu(int pp,int qq){
	p=pp;q=qq;
    }
    public void kiyaku(){
	for(int i=2;i < q+1;){
	    //	    System.out.println(p+" "+q);
	    if(p%i==0 && q%i==0){
		p=p/i;q=q/i;
	    }
	    else{
		i++;
	    }
	}
    }
}

コメント

分数を扱うクラスBunsuを作って,すっきりと解いています.既約分数を作るには, ユークリッドの互除法を使って分子と,分母の最大公約数を求めて,両方をそれで 割るのが一般的ですが,速度を気にしなければ,上のプログラムの方法でも解けます.