2010年9月25日土曜日

Codeforces Beta Round #28

Codeforces Beta Round #28 9/18(0:00~2:00)

久し振りのCodeforces.今回もCodeforces format.

■A. Bender Problem
□問題
複数の釘,長さが異なる複数の(金属)棒がある.釘を頂点,棒を辺として多角形を作れるかどうかを判定せよ.但し,個々の棒は任意の位置で1度折り曲げる必要がある.

□解法
例えば釘が4本,棒が2本とし,釘の座標をp1,p2,p3,p4とする.棒を折り曲げる座標は,p1,p3かp2,p4の2通りとなるため,それぞれが可能かを調べれば良い.

□コード
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class A{
Scanner sc=new Scanner(System.in);

int n, m;

int[] x, y;
int[] rod;

void run(){
n=sc.nextInt();
m=sc.nextInt();
x=new int[n];
y=new int[n];
rod=new int[m];
for(int i=0; i<n; i++){
x[i]=sc.nextInt();
y[i]=sc.nextInt();
}
for(int i=0; i<m; i++)
rod[i]=sc.nextInt();

boolean f1=true;
boolean f2=true;

int[] ans1=new int[n];
boolean[] selected=new boolean[m];

Arrays.fill(ans1, -1);
Arrays.fill(selected, false);
for(int k=0; k<n; k+=2){
// k-1,k,k+1
int x1=x[(k-1+n)%n];
int y1=y[(k-1+n)%n];
int x2=x[k];
int y2=y[k];
int x3=x[k+1];
int y3=y[k+1];
int len1=(int)Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
int len2=(int)Math.sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2));
boolean f=false;
for(int i=0; i<m; i++){
if(!selected[i]&&len1+len2==rod[i]){
selected[i]=true;
ans1[k]=i+1;
f=true;
break;
}
}
if(!f){
f1=false;
break;
}
}

int[] ans2=new int[n];
Arrays.fill(ans2, -1);
Arrays.fill(selected, false);
for(int k=1; k<n; k+=2){
// k-1,k,k+1
int x1=x[k-1];
int y1=y[k-1];
int x2=x[k];
int y2=y[k];
int x3=x[(k+1)%n];
int y3=y[(k+1)%n];
int len1=(int)Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
int len2=(int)Math.sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2));
boolean f=false;
for(int i=0; i<m; i++){
if(!selected[i]&&len1+len2==rod[i]){
selected[i]=true;
ans2[k]=i+1;
f=true;
break;
}
}
if(!f){
f2=false;
break;
}
}

if(f1||f2){
println("YES");
if(f1){
for(int i=0; i<n; i++)
print(ans1[i]+" ");
println("");
}
else if(f2){
for(int i=0; i<n; i++)
print(ans2[i]+" ");
println("");
}
}else{
println("NO");
}

}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new A().run();
}
}


■B. pSort
□問題
n個のセルがある.セルiとセルjはある条件にて各々が持つ値を交換する事が出来る.
初期状態では,n個のセルは,それぞれ1,2,…,n-1,nという値を持っている.
n個のセルの最終状態とどのセル同士が値を交換できるかの情報が与えられた時,初期状態から最終状態への遷移が可能かどうかを判定せよ.

□解法
交換できるセルは互いに素な集合.
例えば,0,…,7まであるとして,
集合1 : 0,3,5,6
集合2 : 1,2,4
集合3 : 7
がそれぞれ互いの値を交換出来る等.
だから,どのセルとどのセルが交換できるかを無向グラフで表現し,強連結成分分解した後,union-find木を作り,最終状態と比較すれば良い(と思う).最終状態は,順番はともかく集合としては,初期状態と同一のもので無ければならない.

□コード
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;

public class B{
Scanner sc=new Scanner(System.in);

int n;
int[] a;
int[] fav;

void run(){
n=sc.nextInt();
a=new int[n];
fav=new int[n];
for(int i=0; i<n; i++)
a[i]=sc.nextInt()-1;
for(int i=0; i<n; i++)
fav[i]=sc.nextInt();

V[] vs=new V[n];
for(int i=0; i<n; i++)
vs[i]=new V(i);
boolean[][] added=new boolean[n][n];
for(int j=0; j<n; j++){
for(int i=0; i<n; i++){
if((Math.abs(j-i)==fav[i]||Math.abs(j-i)==fav[j])&&!added[j][i]){
added[j][i]=true;
vs[i].add(vs[j]);
}
}
}
scc(vs);

parent=new int[n];
rank=new int[n];

for(int i=0; i<n; i++)
makeSet(i);

for(int j=0; j<n; j++)
for(int i=0; i<n; i++)
if(vs[i].comp==vs[j].comp)
union(i, j);

for(int i=0; i<n; i++){
if(!sameComponents(i, a[i])){
println("NO");
return;
}
}
println("YES");
}

void println(String s){
System.out.println(s);
}

void print(String s){
System.out.print(s);
}

public static void main(String[] args){
new B().run();
}

// Union-Find

int[] parent;
int[] rank;

void makeSet(int x){
parent[x]=x;
rank[x]=0;
}

void union(int x, int y){
link(findSet(x), findSet(y));
}

boolean sameComponents(int x, int y){
return findSet(x)==findSet(y);
}

void link(int x, int y){
if(rank[x]>rank[y]){
parent[y]=x;
}else{
parent[x]=y;
if(rank[x]==rank[y])
rank[y]++;
}
}

int findSet(int x){
if(parent[x]!=x)
parent[x]=findSet(parent[x]);
return parent[x];
}

// Strongly Connected Components

int m;
V[] us;

int scc(V[] vs){
m=vs.length;
us=new V[m];
for(V v : vs)
if(!v.visit)
dfs(v);
for(V v : vs)
v.visit=false;
for(V u : us)
if(!u.visit)
dfsrev(u, m++);
return m;
}

void dfs(V v){
v.visit=true;
for(V u : v.fs)
if(!u.visit)
dfs(u);
us[--m]=v;
}

void dfsrev(V v, int k){
v.visit=true;
for(V u : v.rs)
if(!u.visit)
dfsrev(u, k);
v.comp=k;
}

// 頂点
static class V{
// 接続している頂点
LinkedList<V> fs=new LinkedList<V>();
// 接続されている頂点
LinkedList<V> rs=new LinkedList<V>();
boolean visit;
int comp;

int id;
V(int id){
this.id=id;
}

void add(V to){
fs.add(to);
to.rs.add(this);
}
}
}


C以降はどうにも解けませんでした.

■Result
○○×××
998p
158位

■Rating
1851 -> 1759

不覚にもRatingダウン.3問以上解かないとRating上昇は見込めません.

0 件のコメント: