problem1 link
$f[i][L][R]$表示计算到第$i$个,最小最大值是$L,R$时的最少个数。
import java.util.*;
import java.math.*;
import static java.lang.Math.*;
public class ProblemsToSolve {
int[] unique(int[] p) {
int n=p.length;
int[] a=new int[n];
for(int i=0;i<n;++i) {
a[i]=p[i];
}
Arrays.sort(a);
int id=0;
for(int i=1;i<n;++i) {
if(a[i]!=a[id]) {
a[++id]=a[i];
}
}
++id;
if(id==n) {
return a;
}
int[] q=new int[id];
for(int i=0;i<id;++i) {
q[i]=a[i];
}
return q;
}
int getindex(int[] p,int x) {
for(int i=0;i<p.length;++i) {
if(p[i]==x) {
return i;
}
}
return -1;
}
public int minNumber(int[] p,int variety) {
final int n=p.length;
final int[] a=unique(p);
final int m=a.length;
int[][][] f=new int[n][m][m];
for(int i=0;i<n;++i) {
p[i]=getindex(a,p[i]);
}
int result=n;
for(int i=0;i<n;++i) {
for(int j=0;j<m;++j) {
for(int k=0;k<m;++k) {
f[i][j][k]=-1;
}
}
}
f[0][p[0]][p[0]]=1;
for(int i=1;i<n;++i) {
for(int j=i-1;j>=i-2&&j>=0;--j) {
for(int x=0;x<m;++x) {
for(int y=x;y<m;++y) {
if(f[j][x][y]==-1) continue;
if(p[i]>y) {
if(a[p[i]]-a[x]>=variety) {
result=Math.min(result,f[j][x][y]+1);
continue;
}
}
else if(p[i]<x) {
if(a[y]-a[p[i]]>=variety) {
result=Math.min(result,f[j][x][y]+1);
continue;
}
}
final int nx=Math.min(x,p[i]);
final int ny=Math.max(y,p[i]);
if(f[i][nx][ny]==-1||f[i][nx][ny]>f[j][x][y]+1) {
f[i][nx][ny]=f[j][x][y]+1;
}
}
}
}
}
return result;
}
}
problem2 link
$f[i][j]$表示两个分数分别达到$i,j$时选择的最少课程数,并记录选择的课程是哪些。这样进行bfs即可。
import java.util.*;
import java.math.*;
import static java.lang.Math.*;
public class CsCourses {
String int2string(int x) {
if(x<10) {
return "0"+Integer.toString(x);
}
return Integer.toString(x);
}
public int[] getOrder(int[] t, int[] p, int[] e, int skillBound) {
if(skillBound==0) {
return new int[0];
}
final int n=t.length;
int[][] f=new int[51][51];
String[][] d=new String[51][];
boolean[][] inq=new boolean[51][51];
for(int i=0;i<51;++i) {
d[i]=new String[51];
for(int j=0;j<51;++j) {
f[i][j]=-1;
inq[i][j]=false;
}
}
Queue<Integer> que=new LinkedList<>();
for(int i=0;i<n;++i) {
if(t[i]<=1&&p[i]<=1&&e[i]>=1&&t[i]+p[i]>0&&f[t[i]][p[i]]==-1) {
f[t[i]][p[i]]=1;
d[t[i]][p[i]]=int2string(i);
que.offer(t[i]*100+p[i]);
inq[t[i]][p[i]]=true;
}
}
while(!que.isEmpty()) {
final int ii=que.peek()/100;
final int jj=que.peek()%100;
que.poll();
if(ii>=skillBound&&jj>=skillBound) {
continue;
}
for(int k=0;k<n;++k) {
if(t[k]<=ii&&p[k]<=jj) continue;
if(t[k]-ii>1) continue;
if(p[k]-jj>1) continue;
if(e[k]<=f[ii][jj]) continue;
final int nii=Math.max(ii,t[k]);
final int njj=Math.max(jj,p[k]);
if(f[nii][njj]==-1
||f[nii][njj]>f[ii][jj]+1
||f[nii][njj]==f[ii][jj]+1
&&0<d[nii][njj].compareTo(d[ii][jj]+","+int2string(k))) {
f[nii][njj]=f[ii][jj]+1;
d[nii][njj]=d[ii][jj]+","+int2string(k);
if(!inq[nii][njj]) {
que.offer(nii*100+njj);
inq[nii][njj]=true;
}
}
}
}
int num=Integer.MAX_VALUE;
String route="";
for(int i=skillBound;i<51;++i) {
for(int j=skillBound;j<51;++j) {
if(f[i][j]!=-1&&f[i][j]<num||f[i][j]==num&&d[i][j].compareTo(route)<0) {
num=f[i][j];
route=d[i][j];
}
}
}
if(num==Integer.MAX_VALUE) {
return new int[0];
}
String[] path=route.split(",");
int[] result=new int[path.length];
for(int i=0;i<path.length;++i) {
result[i]=Integer.valueOf(path[i]);
}
return result;
}
}
problem3 link
判断一个点在多边形的内部还是外部可以用射线法。一条从某一点发出的射线与多边形有奇数个交点则在内部。
初始时认为每个格子有个垂直向上的射线。每次横着走时,下面的所有格子与多边形的交点个数增加了1.
$f[x][y][mask]$表示从$(0,0)$走到$(x,y)$,经过的$'I'$或者$'X'$的状态是$mask$的最短路。
import java.util.*;
import java.math.*;
import static java.lang.Math.*;
public class VegetableGarden {
public int[] getMinDistances(String[] g) {
final int n = g.length;
final int m = g[0].length();
int id = 0;
int badMask=0;
int iNum=0;
List<Integer> list=new ArrayList<>();
for(int i=0;i<n;++i) {
for(int j=0;j<m;++j) {
if(g[i].charAt(j)!='.') {
if(g[i].charAt(j)=='X') {
badMask|=1<<id;
}
else {
++iNum;
}
list.add(i*100+j);
++id;
}
}
}
int[][][] f=new int[n+1][m+1][1<<id];
boolean[][][] inq=new boolean[n+1][m+1][1<<id];
for(int i=0;i<n+1;++i) {
for(int j=0;j<m+1;++j) {
for(int k=0;k<(1<<id);++k) {
f[i][j][k]=-1;
inq[i][j][k]=false;
}
}
}
Queue<Integer> queue=new LinkedList<>();
f[0][0][0]=0;
inq[0][0][0]=true;
queue.offer(0);
final int[] dx={0,1,0,-1};
final int[] dy={1,0,-1,0};
while(!queue.isEmpty()) {
final int mask=queue.peek()/10000;
final int x=queue.peek()%10000/100;
final int y=queue.peek()%100;
queue.poll();
inq[x][y][mask]=false;
for(int d=0;d<4;++d) {
final int xx=x+dx[d];
final int yy=y+dy[d];
if(xx<0||yy<0||xx>=n+1||yy>=m+1) continue;
int nMask=mask;
if(d==0||d==2) {
final int column=d==0?y:y-1;
for(int k=0;k<list.size();++k) {
final int nx=list.get(k)/100;
final int ny=list.get(k)%100;
if(ny==column&&nx>=x) {
nMask^=1<<k;
}
}
}
if(f[xx][yy][nMask]==-1||f[xx][yy][nMask]>f[x][y][mask]+1) {
f[xx][yy][nMask]=f[x][y][mask]+1;
if(!inq[xx][yy][nMask]) {
inq[xx][yy][nMask]=true;
queue.offer(nMask*10000+xx*100+yy);
}
}
}
}
int[] result=new int[iNum];
for(int i=0;i<(1<<id);++i) {
if((i&badMask)!=0) continue;
if(f[0][0][i]==-1) continue;
int c=0;
int k=i;
while(k!=0) {
c+=k&1;
k>>=1;
}
if(c==0) {
continue;
}
if(result[c-1]==0||result[c-1]>f[0][0][i]) {
result[c-1]=f[0][0][i];
}
}
return result;
}
}