G盲僧与计算几何
题意:给定五个点,求一条直线上最多有几个点
思路:每三个点abc,可以组成两个向量ab和bc,如果两向量平行则两向量在一条直线上(因为有公共点b),向量平行可以用x1*y2=x2*y1判断.如果abc在一条直线上,abd在一条直线上,则abcd都在一条直线上,所以,先枚举前两个点,然后枚举其它点,就可以求出最多有几个点在一条直线上。当然,也可以用斜率算,但有可能会被卡精度,推荐使用乘法。
核心代码:
for(i=1;i<=5;i++){
for(j=i+1;j<=5;j++){
int cnt=2;
for(k=1;k<=5;k++){
if(k!=i && k!=j){
int x1,x2,y1,y2;
x1=a[j].x-a[i].x;
y1=a[j].y-a[i].y;
x2=a[k].x-a[j].x;
y2=a[k].y-a[j].y;
if(x1*y2==x2*y1)
cnt++;
}
}
ma=max(ma,cnt);
}
}
H魔刹石与数据芯片
题意:n分钟,两个工地,两种材料,每分钟可以换工地,或在当前工地工作,或出售背包中的材料,求最大收益
思路:由于对于每分钟可以进行多种不同操作,无后效性,所以可以用动态规划来做。带有一点贪心的思想,同时卖两种材料一定不是最优解,因为每分钟得到的材料数固定,收益只与卖的时候的价格有关,在第i分钟,如果卖第一种材料收益更高(time*x*val1>time*y*val2),那么就让它在上一次买材料后全部时间来搬第一种材料,抽时间搬第二种材料收益一定更低,所以收益最大化一定是在当前工地卖当前材料。
如果在第i分钟卖第一种材料可以使收益最大化,那么前一个状态就是在第j分钟(j<i)卖完某种材料后到第一个工地一直搬到第i分钟然后出售
用dp[n][m]表示第n分钟时进行m操作的总收益,另0代表在工地1搬砖,1代表在工地2搬砖,2代表卖材料1,3代表卖材料2。则:
dp[i][2]=max(dp[i][2],dp[j][2]+(i-j-1)*val1[i]*x);
dp[i][2]=max(dp[i][2],dp[j][1]+(i-j-1)*val1[i]*x);
dp[i][2]=max(dp[i][2],dp[j][0]+(i-j)*val1[i]*x);
dp[i][2]=max(dp[i][2],dp[j][3]+(i-j-2)*val1[i]*x);
dp[i+1][0]=dp[i][2];
dp[i][3]=max(dp[i][3],dp[j][0]+(i-j-1)*val2[i]*y);
dp[i][3]=max(dp[i][3],dp[j][3]+(i-j-1)*val2[i]*y);
dp[i][3]=max(dp[i][3],dp[j][2]+(i-j-2)*val2[i]*y);
dp[i][3]=max(dp[i][3],dp[j][1]+(i-j)*val2[i]*y);
dp[i+1][1]=dp[i][3];
这样写有一些多余的状态,有些状态转移一定不会是最优,但思路清晰,理解后可以自行尝试去掉冗余的状态转移。
因为初始在工地1,所以dp[1][2]和dp[1][3]是不存在的,需要特判.
两层循环(i,1-n),(j,1-i) 时间复杂度O(n2),空间复杂度O(n)