P - Beat
思路:这道题给的图理解了蛮久,a[i][j] 表示做完第i题之后做第j题要花费的时间
理解这个后就可以dfs第i行搜索花费时间不少于第i题且未做过的题+回溯
#include
using namespace std;
const int maxn = 20;
int n;
int a[maxn][maxn];
bool vis[maxn];
int ans;
void dfs(int cnt,int w,int x) {
if (cnt > ans) {
ans = cnt;
}
for (int i = 2; i <= n; i++) {
if (!vis[i] && a[x][i] >= w) {
vis[i] = 1;
dfs(cnt + 1, a[x][i],i);
vis[i] = 0; //回溯
}
}
}
int main()
{
ios::sync_with_stdio(false);
while (cin >> n) {
ans = 0; //重置ans,方便下一组数据使用
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
dfs(1,0,1);
cout << ans << '\n';
}
return 0;
}
Q - 生日蛋糕
思路:这道题以前上网课讲过,现在写还算比较有思路
将当前目标体积半径及层数代入dfs,同时dfs还需记录当前层数,体积,面积
从当前目标体积半径及层数--的方式开始枚举,利用公式继续dfs,遇见层数=目标层数,体积=目标体积记录最小面积
其中可行性剪枝:可将高度近似于半径处理,预处理每一级体积得到每一级最大体积,目前体积+可能的最大体积>n 返回
最优性剪枝:(目前面积+2*(所需体积-目前体积)/最大半径)>ans返回
#include
#include
#include
using namespace std;
const int INF = 0x3f3f3f3f;
int n, m;
int ans;
int va[20];
void dfs(int u, int v, int s, int r0, int h0)
{
if (u == m) { //层数
if (v == n) { //体积
ans = min(ans, s); //面积
}
return;
}
if (va[m - u] + v > n)return; //可行性剪枝:目前体积+可能的最大体积>n 返回
if (2.0 * (n - v) / r0 + s > ans)return; ///最优性剪枝:预处理(目前面积+2*(所需体积-目前体积)/半径)>ans返回
for (int r = r0; r >= m - u; r--) {
for (int h = h0; h >= m - u; h--) {
int tv = v + r * r * h;
if (tv > n)
continue;
int ts = s + 2 * r * h;
if (u == 0)ts += r * r; ///计算顶层
dfs(u + 1, tv, ts, r - 1, h - 1);
}
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i <= m; i++) {
va[i] = va[i - 1] + i * i * i;
}
int r0 = sqrt(n) + 0.5; //向上取整
ans = INF;
dfs(0, 0, 0, r0, n);
if (ans == INF)ans = 0;
cout << ans <<'\n';
return 0;
}
G - Find a way
思路:确定Y,M的起点,用队列将每个KFC的位置储存,两次bfs将Y,M,到每个位置的KFC最短路径储存
比较Y和M到同一KFC的最短路径和的最小值,最小值*11得到答案
#include
#include
#include
using namespace std;
const int maxn = 210;
char mp[maxn][maxn];
int vis[maxn][maxn][2];
int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} }; //方向
int n, m;
struct node{
int x, y;
}Y, M;
bool in(int x,int y) {
return x > 0 && x <= n && y > 0 && y <= m;
}
void bfs(node now, int z)
{
queueq;
q.push(now);
while (!q.empty())
{
node w = q.front();
q.pop();
for (int i = 0; i < 4; ++i)
{
int x = w.x + dir[i][0];
int y = w.y + dir[i][1];
if (in(x,y) && !vis[x][y][z] && mp[x][y] != '#')
{
vis[x][y][z] = vis[w.x][w.y][z] + 1;
q.push({ x,y });
}
}
}
}
int main()
{
while (cin >> n >> m)
{
memset(vis, 0, sizeof vis);
queuep;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j)
{
cin >> mp[i][j];
if (mp[i][j] == 'Y')
Y.x = i, Y.y = j;
if (mp[i][j] == 'M')
M.x = i, M.y = j;
if (mp[i][j] == '@')
p.push({ i,j });
}
}
bfs(Y, 1);
bfs(M, 0);
int Min = 0x3f3f3f3f;
while (p.size())
{
node w = p.front();
p.pop();
if (vis[w.x][w.y][0] && vis[w.x][w.y][1])
Min = min(Min, vis[w.x][w.y][0] + vis[w.x][w.y][1]);
}
cout << Min * 11 << endl;
}
return 0;
}
Codeforces Round 858 (Div. 2)
B.Mex Master
思路:题意理解了好久,终于找到突破口,根据题意如果全为>=1的数,结果为0,于是考虑存在0的情况,
0的个数<=非0个数+1,可以0与非0交叉排放,结果为0;如果0的个数>非0个数+1,结果不可能为0,只能构造结果为1,考虑存在1的情况
0,1个数<总个数,于是可以变成000...x1x2x3...111的形式,结果为1,最后如果全为0,1,结果为2;
经调试发现还少了一种特殊情况,即0,1个数=总个数,但1个数=0(全为0情况)结果为0;于是情况全覆盖
#include
#include
using namespace std;
int main() {
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int a = 0, b = 0;
for (int i = 1; i <= n; i++) {
int d;
cin >> d;
if (d == 0)
a++;
if (d == 1)
b++;
}
if (a <= (n + 1) / 2) {
cout << 0 << '\n';
}
else {
if (a + b < n) {
cout << 1 << '\n';
continue;
}
if (b == 0) {
cout << 1 << '\n';
continue;
}
cout << 2 << '\n';
}
}
return 0;
}
java学习日志(2)
6.Java的子类与继承
(1)子类与父类,子类的继承性,Java子类与对象(继承性)
某个类有我们所需要的成员变量和方法,如果我们想复用这个类中的成员变量和方法,即在所编写的类中不用声明成员变量和定义方法,就相当于有了这个成员变量和方法,那么我们可以将编写的类定义为这个类的子类。
格式为:
class 子类名 extends 父类名 {
…
}
注:类的树形结构中,根结点是Object类,每个类(除了Object类)有且仅有一个父类,一个类可以有多个或零个子类。如果一个类(除了Object类)的声明中没有使用extends关键字,这个类被系统默认为是Object的子类。
同一包中的继承性:子类继承了其父类中不是private的成员变量,方法作为自己的成员变量,方法
不在同一包中的继承性:子类只继承父类中的protected和public访问权限的成员变量和方法
Java子类与对象:当用子类的构造方法创建一个子类的对象时,不仅子类中声明的成员变量被分配了内存,而且父类的成员变量也都分配了内存空间,但只将子类继承的那部分成员变量作为分配给子类对象的变量。(个人理解为尽量在父类中创建可共用变量和方法,先执行父类构造,再执行子类构造,否则浪费空间)
(2)java成员变量的隐藏和方法重写
子类所声明的成员变量的名字和从父类继承来的成员变量的名字相同,声明的类型可以不同,在这种情况下,子类就会隐藏所继承的成员变量,使用的是子类声明的成员变量,而不是父类的。
方法重写:子类中定义一个方法,这个方法的类型和父类的方法的类型一致或者是父类的方法的类型的子类型,并且这个方法的名字、参数个数、参数的类型和父类的方法完全相同。子类如此定义的方法称作子类重写的方法,不属于新增的方法。子类通过重写可以隐藏已继承的方法。
注:重写父类的方法时,不允许降低方法的访问权限,但可以提高访问权限
(3)super关键字
super操作被隐藏的成员变量和方法
子类一旦隐藏了继承的成员变量和方法,那么子类创建的对象就不再拥有该变量和方法,该变量和方法将归关键字super所拥有,如果在子类中想使用被子类隐藏的成员变量或方法就需要使用关键字super。使用:
1). super.XXX(XXX指的是父类的成员变量名即父类的属性,或者对象名) 2). super.XXX( ) (XXX是父类中的其中一个方法名)
用super调用父类的构造方法
当用子类的构造方法创建一个子类的对象时,子类的构造方法总是先调用父类的某个构造方法,也就是说,如果子类的构造方法没有明显地指明使用父类的哪个构造方法,子类就调用父类的不带参数的构造方法。由于子类不继承父类的构造方法,因此,子类在其构造方法中需使用super来调用父类的构造方法,而且super必须是子类构造方法中的头一条语句,即如果在子类的构造方法中,没有明显地写出super关键字来调用父类的某个构造方法,那么默认地有:
super ();
使用:
3). super( ) ( 这种形式指的是:调用父类没有参数的构造方法(也叫构造函数) 这里super( ) 只能放在子类的构造方法里面,并且只能放在构造方法的首句)
4).super( x,y,z...) (此形式指:调用父类有参数的构造方法,也必须放在子类的构造方法(成员方法不可以)里面,并且只能放在构造方法的首句。其中x,y,z是指的与父类此有参构造方法中参数数据类型相对应的子类中的参数)
(4)final关键字
final关键字可以修饰类、成员变量和方法中的局部变量,使用关键字final将类声明为final类,final类不能被继承,即不能有子类。如果成员变量或局部变量被修饰为final,那它就是常量。由于常量在运行期间不允许再发生变化,所以常量在声明时没有默认值,这就要求程序在声明常量时必须指定该常量的值。
(5)Java对象的上转型对象
例:假设Animal类是Tiger类的父类,当用子类创建一个对象,并把这个对象的引用放到父类的对象中时,
Animal a;
a = new Tiger();
对象的上转型对象的实体是子类负责创建的,但上转型对象会失去原对象的一些属性和功能。
注:上转型对象不能操作子类新增的成员变量,不能调用子类新增的方法。
上转型对象可以访问子类继承或隐藏的成员变量,也可以调用子类继承的方法或子类重写的实例方法
可以将对象的上转型对象再强制转换到一个子类对象,这时,该子类对象又具备了子类所有的属性和功能。不可以将父类创建的对象的引用赋值给子类声明的对象。
(6)java的继承与多态(多态性)
多态性就是指父类的某个方法被其子类重写时,可以各自产生自己的功能行为。
class 动物 {
void cry() {
}
}
class 狗 extends 动物 {
void cry() {
System.out.println("wangwang");
}
}
class 猫 extends 动物 {
void cry() {
System.out.println("miaomiao");
}
}
public class Main {
public static void main(String args[]) {
动物 animal;
animal = new 狗();
animal.cry();
animal = new 猫();
animal.cry();
}
}
(7)抽象类,抽象方法,普通方法
父类是将子类所共同拥有的属性和方法进行抽取,这些属性和方法中,有的是已经明确实现了的,有的还无法确定,那么我们就可以将其定义成抽象,在后日子类进行重用,进行具体化。
例:
abstract class A{//定义一个抽象类
//普通方法
public void fun(){
System.out.println("存在方法体的方法");
}
//抽象方法,没有方法体,有abstract关键字做修饰
public abstract void print();
}
对于abstract方法,只允许声明,不允许实现,即没有方法体,abstract类中可以有abstract方法,也可以有非abstract方法,而非abstract类中不可以有abstract方法。
对于abstract类,不能使用new运算符创建该类的对象,如果一个非abstract类是某个abstract类的子类,那么它必须重写父类的抽象方法,并给出方法体,
使用abstract类声明对象,尽管不能使用new运算符创建该对象,但是该对象可以成为其子类对象的上转型对象,这样该对象就可以调用子类重写的方法。
注意:abstract类可以没有abstract方法,如果一个abstract类是abstract类的子类,那么它既可以重写父类的abstract方法,也可以继承父类的abstract方法。
7.java接口与实现
(1)java接口
通常使用关键字interface来定义一个接口,接口的定义分为接口声明和接口体
接口声明:interface 接口的名字
接口体:包含常量的声明和抽象方法两部分,接口体中只有抽象方法,而且接口体中所有的常量的访问权限一定都是public,而且是static常量,所有的抽象方法的访问权限一定都是public,例:
interface Printable {
public final static int MAX = 100; //等价写法:int MAX = 100;
public abstract void add(); //等价写法:void add();
public abstract float sum(float x,float y);
//等价写法:float sum(float x,float y);
}
注:修饰符public、final、static允许省略。
(2)java实现接口:
Java语言中,接口由类来实现,以便使用接口中的方法。一个类需要在类声明中使用关键字implements声明该类实现一个或多个接口。如果实现多个按口,用逗号隔开接口名。