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;
}
}