topcoder srm 360 div1
problem1 link
(1)$n \neq m$时,假设$n<m$,那么同一行中的$m$个数字必定都相等。
(2)$n=m$时,要满足任意的$i_{1},i_{2},j_{1},j_{2},A[i_{1}][j_{1}]+A[i_{2}][j_{2}]=A[i_{1}][j_{2}]+A[i_{2}][j_{1}]$
import java.util.*; import java.math.*; import static java.lang.Math.*; public class SumOfSelectedCells { public String hypothesis(String[] table) { final String YES="CORRECT"; final String NO="INCORRECT"; final int n=table.length; int m=-1; int[][] g=new int[22][22]; for(int i=0;i<n;++i) { String[] t=table[i].split("\\W+"); if(m==-1) { m=t.length; } else { assert m==t.length; } for(int j=0;j<m;++j) { g[i][j]=Integer.valueOf(t[j]); } } if(n!=m) { if(n<m) { for(int i=0;i<n;++i) { for(int j=1;j<m;++j) { if(g[i][0]!=g[i][j]) { return NO; } } } } else { for(int j=0;j<m;++j) { for(int i=1;i<n;++i) { if(g[0][j]!=g[i][j]) { return NO; } } } } } else { for(int i1=0;i1<n;++i1) { for(int i2=i1+1;i2<n;++i2) { for(int j1=0;j1<m;++j1) { for(int j2=j1+1;j2<m;++j2) { if(g[i1][j1]+g[i2][j2]!=g[i1][j2]+g[i2][j1]) { return NO; } } } } } } return YES; } }
problem2 link
仅当相邻时无解。有解时答案最大为4.因为可以将其中的一个围住。那么只需要检测小于4时是否可以。这时,可以暴力枚举然后判断连通性。
import java.util.*; import java.math.*; import static java.lang.Math.*; public class PrinceOfPersia { static class pair { public int first; public int second; public pair() {} public pair(int first,int second) { this.first=first; this.second=second; } } int[][] visit=null; int index=0; int sx=-1,sy=-1,ex=-1,ey=-1; String[] maze=null; final int[] dx={0,0,1,-1}; final int[] dy={1,-1,0,0}; int n,m; List<pair> empty=null; boolean dfs(int x,int y) { if(x==ex&&y==ey) { return true; } if(x<0||x>=n||y<0||y>=m||maze[x].charAt(y)=='#') { return false; } if(index==visit[x][y]) { return false; } visit[x][y]=index; for(int i=0;i<4;++i) { if(dfs(x+dx[i],y+dy[i])) { return true; } } return false; } int cal() { ++index; if(!dfs(sx,sy)) { return 0; } for(int i=0;i<empty.size();++i) { ++index; visit[empty.get(i).first][empty.get(i).second]=index; if(!dfs(sx,sy)) { return 1; } } for(int i=0;i<empty.size();++i) { for(int j=i+1;j<empty.size();++j) { ++index; visit[empty.get(i).first][empty.get(i).second]=index; visit[empty.get(j).first][empty.get(j).second]=index; if(!dfs(sx,sy)) { return 2; } } } for(int i=0;i<empty.size();++i) { for(int j=i+1;j<empty.size();++j) { for(int k=j+1;k<empty.size();++k) { ++index; visit[empty.get(i).first][empty.get(i).second]=index; visit[empty.get(j).first][empty.get(j).second]=index; visit[empty.get(k).first][empty.get(k).second]=index; if(!dfs(sx,sy)) { return 3; } } } } return 4; } public int minObstacles(String[] maze) { this.maze=maze; n=maze.length; m=maze[0].length(); visit=new int[n][m]; empty=new ArrayList<>(); for(int i=0;i<n;++i){ for(int j=0;j<m;++j) { if(maze[i].charAt(j)=='P') { if(sx==-1) { sx=i; sy=j; } else { ex=i; ey=j; } } else if(maze[i].charAt(j)=='.') { empty.add(new pair(i,j)); } } } if(sx==ex&&Math.abs(sy-ey)==1||sy==ey&&Math.abs(sx-ex)==1) { return -1; } return cal(); } }
problem3 link
设$m$ 为给出的数字个数.对于一个凸包,假设顶点大于3,那么去掉任意一个顶点后仍是凸包。所以:
(1)$m\geq 6$时,若为奇数只需要添加一个数字(这时可以暴力),为偶数不需要添加;
(2)$m<6$时,需要添加$6-m$个数字。$m=2,3,4,5$时可以暴力;$m=0$时答案为$1,1,1,2,2,1$,$m=1$时,若给出的数字为1则答案为$1,1,2,2,1$,否则答案为$1,1,1,1,2$
那么,剩下的问题就是判断凸包,只需判断:(1)任意三个点角度小于180;(2)任意两条边不相交(这个只需要判断$y$连续严格增大的顶点段的个数以及$y$严格减小的连续顶点段的个数,为凸包时这些段数最大为3)
import java.util.*; import java.math.*; import static java.lang.Math.*; public class ConvexArray { static class point { public long x; public long y; public point() {} public point(long x,long y) { this.x=x; this.y=y; } public point add(point a) { return new point(x+a.x,y+a.y); } public point substract(point a) { return new point(x-a.x,y-a.y); } public long crossMultiply(point a) { return x*a.y-y*a.x; } } boolean check(List<Integer> list) { final int n=list.size()>>1; List<point> g=new ArrayList<>(); for(int i=0;i<n;++i) { g.add(new point(list.get(i<<1),list.get(i<<1|1))); } long a=0; for(int i=0;i<n;++i) { a+=g.get(i).crossMultiply(g.get((i+1)%n)); } if(a==0) { return false; } if(a<0) { int ll=0,rr=n-1; while(ll<rr) { point p=g.get(ll); point q=g.get(rr); g.set(ll,q); g.set(rr,p); ++ll; --rr; } } for(int i=0;i<n;++i) { point p=g.get(i); point q=g.get((i+1)%n); point r=g.get((i+2)%n); if(q.substract(p).crossMultiply(r.substract(p))<=0) { return false; } } int num=0; for(int i=0;i<n;) { if(g.get(i).y<g.get((i+1)%n).y) { ++num; while(g.get(i).y<g.get((i+1)%n).y) { ++i; if(i==n) { break; } } } else if(g.get(i).y>g.get((i+1)%n).y) { ++num; while(g.get(i).y>g.get((i+1)%n).y) { ++i; if(i==n) { break; } } } else { ++i; } } if(num>3) { return false; } return true; } public int[] getEnding(int[] beginning) { final int n=beginning.length; if(n>=6) { List<Integer> list=new ArrayList<>(); for(int i=0;i<n;++i) { list.add(beginning[i]); } if(n%2==1) { list.add(0); for(int i=1;i<=50;++i){ list.set(list.size()-1,i); if(check(list)) { return new int[]{i}; } } return new int[]{-1}; } else { if(check(list)) { return new int[0]; } else { return new int[]{-1}; } } } if(n==0) { return new int[]{1,1,1,2,2,1}; } if(n==1) { final int x=beginning[0]; if(x==1) { return new int[]{1,1,2,2,1}; } return new int[]{1,1,1,1,2}; } List<Integer> list=new ArrayList<>(); for(int i=0;i<n;++i) { list.add(beginning[i]); } while(list.size()<6) { list.add(0); } if(dfs(n,list)) { int[] result=new int[6-n]; for(int i=n;i<6;++i) { result[i-n]=list.get(i); } return result; } return new int[]{-1}; } boolean dfs(int t,List<Integer> list) { if(t==6) { return check(list); } for(int i=1;i<=50;++i) { list.set(t,i); if(dfs(t+1,list)) { return true; } } return false; } }