Spiral Pattern(AOJ No.0141), Nature of Prime Numbers(AOJ No.0142), Altair and Vega(AOJ No.0143), Packet Transportation(AOJ No.0144), Cards(AOJ No.0145)
Spiral Pattern(AOJ No.0141)
nが与えられて、n×nの中にぐるぐる模様を書く。
ぐるぐる模様は、左下から始まって1行または1列分開けて中心に向かって'#'で描かれる。↑のリンク参照
アルゴリズム
進行方向とその4近傍(自分がいる位置を除く)を見て'#'なら方向転換、' 'なら進む。
方向転換した後、上の操作で進めないならそこで終了。
コード
方向ベクトルを作っとけば多少楽になる
番兵として' 'で囲んだ後に、さらに'#'で囲んでいる。
import java.util.*; public class aoj0141 { static final Scanner stdin = new Scanner(System.in); static final int dx[] = {0, 1, 0, -1}; static final int dy[] = {-1, 0, 1, 0}; static char[][] map; static boolean check(int x, int y, int dir){ int nx = x + dx[dir], ny = y + dy[dir]; if(map[ny][nx] == '#') return false; //この条件多分いらない for(int i = 0; i < 4; ++i){ if(nx + dx[i] == x && ny + dy[i] == y) continue; if(map[ny + dy[i]][nx + dx[i]] == '#') return false; } return true; } public static void main(String[] args) { int d = stdin.nextInt(); while(d-- > 0){ int n = stdin.nextInt(); map = new char[n+4][n+4]; for(int i = 0; i < n+4; ++i) for(int j = 0; j < n+4; ++j) map[i][j] = (i == 0 || j ==0 || i == n+3 || j == n+3) ? '#' : ' '; int dir = 0, x = 2, y = n+2; boolean flag = false; //方向転換したかどうか while(true){ if(check(x, y, dir)){ x += dx[dir]; y += dy[dir]; flag = false; map[y][x] = '#'; }else if(flag){ break; }else{ dir = (dir + 1) % 4; flag = true; } } for(int i = 2; i < n+2; ++i){ for(int j = 2; j < n+2; ++j) System.out.print(map[i][j]); System.out.println(); } if(d > 0) System.out.println(); } } }
Nature of Prime Numbers(AOJ No.0142)
nが与えれる。
について、
の操作を行い、xの頻度表を作る。
制約
は奇数
コード
普通にやるだけでは駄目だと思い込んでいたが、そんなことは無かった。
import java.util.*; public class aoj0142 { static final Scanner stdin = new Scanner(System.in); public static void main(String[] args) { while(true){ int n = stdin.nextInt(); if(n == 0) break; int[] freq = new int[(n-1)/2+1]; Arrays.fill(freq, 0); Set<Integer> set = new HashSet<Integer>(); for(int i = 1; i < n; ++i) set.add(i*i%n); Integer[] a = set.toArray(new Integer[set.size()]); for(int i = 0; i < a.length; ++i){ for(int j = 0; j < a.length; ++j){ if(i == j) continue; int x = a[i] - a[j]; if(x < 0) x += n; if(x > (n-1)/2) x = n - x; freq[x]++; } } for(int i = 1; i < freq.length; ++i) System.out.println(freq[i]); } } }
Altair and Vega(AOJ No.0143)
三角形の3頂点の位置P1(xp1,yp1), P2(xp2,yp2), P3(xp3,yp3)
牽牛の位置K(xk,yk)
織女の位置S(xs,ys)
が与えられ、三角形の内側と外側で領域が分かれている。
牽牛と織女が同じ領域にいるかどうかを判定する。
アルゴリズム
以前作った点が多角形の内部にあるかどうかを判定するライブラリ(http://kanetai.hatenablog.com/entry/20120610/1339328126)を使う。
あるいは、面積△P1P2P3 = △xP2P3 + △P1xP3 + △P1P2x となるかどうかで判定
コード
import java.util.*; import java.awt.geom.*; public class aoj0143 { static final Scanner stdin = new Scanner(System.in); static final double EPS = 1e-10; static final Solver solver = Solver.CONTAINS; public static void main(String[] args) { int n = stdin.nextInt(); while(n-- > 0){ Point[] p = new Point[3]; for(int i = 0; i < 3; ++i) p[i] = new Point(stdin.nextDouble(), stdin.nextDouble()); Point k = new Point(stdin.nextDouble(), stdin.nextDouble()); Point s = new Point(stdin.nextDouble(), stdin.nextDouble()); System.out.println(solver.solve(p, k, s) ? "OK" : "NG"); } } static enum Solver { CONTAINS { @Override boolean solve(Point[] p, Point k, Point s){ return contains(p, k) != contains(p, s);} }, SQUARE { @Override boolean solve(Point[] p, Point k, Point s){ double S = square(p), Sk = 0, Ss = 0; for(int i = 0; i < 3; ++i){ Point temp = p[i]; p[i] = k; Sk += square(p); p[i] = s; Ss += square(p); p[i] = temp; } return equal(S, Sk) != equal(S, Ss); } }; boolean solve(Point[] p, Point k, Point s){ return true; } } public static boolean equal(double a, double b){ return Math.abs(a-b) < EPS; } public static boolean leq(double a, double b){ return a - b < EPS; } @SuppressWarnings("serial") public static class Point extends Point2D.Double { public Point(double x, double y){ super(x,y); } public final Point sub(Point p){ return new Point( x - p.x, y - p.y ); } public final double cross(Point p){ return x * p.y - y * p.x; } public final double dot(Point p){ return x * p.x + y * p.y; } } //class Point public static boolean contains(Point[] polygon, Point p) { boolean in = false; for (int i = 0, n = polygon.length; i < n; ++i) { Point a = polygon[i].sub(p), b = polygon[(i+1)%n].sub(p); if (a.y > b.y){ Point temp = b; b = a; a = temp; } if (a.y <= 0 && 0 < b.y) //点pからxの正方向への半直線が多角形の頂点をとおるとき、最終的に交差数を偶数回にするためどちらかを<=ではなく、<にする if (a.cross(b) < 0) in = !in; //=0 -> a//b -> on if (equal(a.cross(b), 0) && leq(a.dot(b), 0)) return true; //on edge } return in; //in out } public static double square(Point[] polygon){ int n = polygon.length; double res = 0.0; for(int i = 0; i < n; ++i){ Point cur = polygon[i], next = polygon[(i+1)%n]; res += (cur.x + next.x)*(cur.y - next.y); } return Math.abs(res/2.0); } }
Packet Transportation(AOJ No.0144)
有向グラフと、パケットの始点s, 終点e, TTL(Time to Live)が与えられて、
sからeに到達する最短時間(ホップ数+1)を求める。最短到達時間>TTLなら"NA"と答える。
コード
ワーシャルフロイドでおk
ノード数nのとき、ノード番号が1〜nまでの自然数で振られるとは問題に書いてなかったので、名前表を作った。
import java.util.*; public class aoj0144 { static final Scanner stdin = new Scanner(System.in); static final int INF = Integer.MAX_VALUE/2; static int idx = 0; static Map<String, Integer> name; static int[][] M; static int get(String s){ if(name.containsKey(s)) return name.get(s); name.put(s, idx); return idx++; } public static void main(String[] args) { int n = stdin.nextInt(); stdin.nextLine(); name = new HashMap<String, Integer>(n+n); M = new int[n][n]; for(int i = 0; i < n; ++i){ Arrays.fill(M[i], INF); M[i][i] = 0; } for(int i = 0; i < n; ++i){ String[] s = stdin.nextLine().split(" "); int src = get(s[0]); for(int j = 2; j < s.length; ++j) M[src][get(s[j])] = 1; } APSPResult res = FloydWarshall(M); int p = stdin.nextInt(); stdin.nextLine(); for(int i = 0; i < p; ++i){ String[] s = stdin.nextLine().split(" "); int ans = res.getDist(get(s[0]), get(s[1])) + 1; System.out.println(ans >= INF || ans > Integer.parseInt(s[2]) ? "NA" : ans ); } } @SuppressWarnings("unused") public static class APSPResult{ private int[][] dist; // dist[d]:= shortest path to d private int[][] prev; // back pointers private boolean hasNegativeCycle; public APSPResult(int[][] dist, int[][] prev, boolean hasNegativeCycle){ set(dist, prev, hasNegativeCycle); } final private void set(int[][] dist, int[][] prev, boolean hasNegativeCycle){ this.dist = dist; this.prev = prev; this.hasNegativeCycle = hasNegativeCycle; } final public int getDist(int i, int j){ return dist[i][j]; } } public static APSPResult FloydWarshall(int[][] G){ int n = G.length; int[][] prev = new int[n][n], dist = new int[n][n]; for(int i = 0; i < n; ++i){ System.arraycopy(G[i], 0, dist[i], 0, n); dist[i][i] = 0; for(int j = 0; j < n; ++j) prev[i][j] = (G[i][j] != INF ? i : -1); } for(int k = 0; k < n; ++k){ for(int i = 0; i < n; ++i){ if(dist[i][k] >= INF) continue; for(int j = 0; j < n; ++j){ int newDist = dist[i][k] + dist[k][j]; if(dist[i][j] > newDist){ dist[i][j] = newDist; prev[i][j] = prev[k][j]; } } } } boolean hasNegativeCycle = false; for(int i = 0; i < n; ++i) if(dist[i][i] < 0){ hasNegativeCycle = true; break; } return new APSPResult(dist, prev, hasNegativeCycle); } }
Cards(AOJ No.0145)
数字が書かれたカードの山iがn個ある。
山の一番上のカードの数字と一番下のカードの数字が与えられる。()
隣り合う山iとi+1をマージすると一番上のカードが, 一番したのカードがになって、マージコストにかかる。
全てマージして山を一つにしたときの最小コストを求める。
制約
最大マージコスト
アルゴリズム
を山iから山jをマージするための最大コストとする。
初期値は、
計算は、について、
コード
ループでDPしようとしたら、ループの順序間違って、WAだした。
となり同士をマージして段々i,jの範囲(d)を広げながら、一番内側でkをまわさないといけない(solve1)
この場合、メモ化再帰で解く方が簡単かなぁ(solve2)
import java.util.*; public class aoj0145 { static final Scanner stdin = new Scanner(System.in); static final int INF = Integer.MAX_VALUE/2; static int n, a[], b[], dp[][]; static Solver solver = Solver.SOLVE1; public static void main(String[] args) { n = stdin.nextInt(); dp = new int[n][n]; a = new int[n]; b = new int[n]; for(int i = 0; i < n; ++i){ a[i] = stdin.nextInt(); b[i] = stdin.nextInt(); for(int j = 0; j < n; ++j) dp[i][j] = (i == j ? 0 : INF); } System.out.println(solver.solve()); } static enum Solver { SOLVE1 { @Override int solve(){ for(int d = 0; d < n; ++d){ for(int i = 0; i+d < n; ++i){ int j = i + d; for(int k = i; k < j; ++k){ dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k+1][j] + a[i]*b[k]*a[k+1]*b[j] ); } } } return dp[0][n-1]; }}, SOLVE2 { @Override int solve(){ return rec(0, n-1); } int rec(int i, int j){ if(i == j) return 0; if(dp[i][j] < INF) return dp[i][j]; for(int k = i; k < j; ++k) dp[i][j] = Math.min(dp[i][j], rec(i, k) + rec(k+1, j) + a[i]*b[k]*a[k+1]*b[j]); return dp[i][j]; } }; int solve(){ return 0;} } }