at B-Points on Plane
思路:想到一个很好的思路,在菱形中假设取正方形估算出大概值,开方后此值一定<=期待值,
于是,逐步++构造更大的正方形逼近囊括期待的菱形即可
#include
#include
#include
using namespace std;
typedef long long ll;
int main() {
int t;
cin >> t;
while (t--) {
ll n;
cin >> n;
if (n == 1) {
cout << 0 <<'\n';
continue;
}
if (n <= 4) {
cout << 1 <<'\n';
continue;
}
ll ans = (ll)sqrt(n);
while (ans * ans < n)ans++; //处理ll直接开方的精度丢失问题
cout << ans - 1 << endl;
}
return 0;
}
T - Open the Lock
思路:双向bfs执行+1操作和交换操作,从前往后有交叉或从后往前有交叉return
#include
#include
#include
using namespace std;
const int maxn = 1e4 + 10;
struct node{
int a[4];
int step;
}s, e;
int vis[maxn];//标记当前状态是否有走过(从前往后走为1,从后往前走为2,没有走过为0)
int mp[maxn];//标记走到当前状态的步数
int get_num(int c[])
{
int n = 0;
for (int i = 0; i < 4; i++){
n *= 10;
n += c[i];
}
return n;
}
int bfs()
{
memset(vis, 0, sizeof(vis));
memset(mp, 0, sizeof(mp));
queuep, q;
int tmp;
tmp = get_num(s.a);
vis[tmp] = 1;
tmp = get_num(e.a);
vis[tmp] = 2;
node u, v;
p.push(s);
q.push(e);
while (!q.empty() || !p.empty())
{
if (!p.empty()){
u = p.front();
p.pop();
for (int i = 0; i < 4; i++){ //+1操作
v = u;
v.a[i] = u.a[i] + 1;
if (v.a[i] == 10)
v.a[i] = 1;
tmp = get_num(v.a);
if (vis[tmp] == 0)//从前往后没有走过
{
v.step = u.step + 1;
mp[tmp] = v.step;//标记走到当前状态的步数
vis[tmp] = 1;
p.push(v);
}
else if (vis[tmp] == 2)//从前往后与从后往前有交叉
return u.step + mp[tmp] + 1;
v.a[i] = u.a[i] - 1; //-1操作
if (v.a[i] == 0)
v.a[i] = 9;
tmp = get_num(v.a);
if (vis[tmp] == 0)
{
v.step = u.step + 1;
mp[tmp] = v.step;
vis[tmp] = 1;
p.push(v);
}
else if (vis[tmp] == 2)
return u.step + mp[tmp] + 1;
}
for (int i = 0; i < 3; i++)//交换
{
v = u;
int k = v.a[i]; //交换
v.a[i] = v.a[i + 1];
v.a[i + 1] = k;
tmp = get_num(v.a);
if (vis[tmp] == 0)
{
v.step = u.step + 1;
mp[tmp] = v.step;
vis[tmp] = 1;
p.push(v);
}
else if (vis[tmp] == 2)
return u.step + mp[tmp] + 1;
}
}
if (!q.empty())
{
u = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
v = u;
v.a[i] = u.a[i] + 1;
if (v.a[i] == 10)
v.a[i] = 1;
tmp = get_num(v.a);
if (vis[tmp] == 0)
{
v.step = u.step + 1;
mp[tmp] = v.step;
vis[tmp] = 2;
q.push(v);
}
else if (vis[tmp] == 1)//从后往前与从前往后有交叉
return u.step + mp[tmp] + 1;
v.a[i] = u.a[i] - 1;
if (v.a[i] == 0)
v.a[i] = 9;
tmp = get_num(v.a);
if (vis[tmp] == 0){
v.step = u.step + 1;
mp[tmp] = v.step;
vis[tmp] = 2;
q.push(v);
}
else if (vis[tmp] == 1)
return u.step + mp[tmp] + 1;
}
for (int i = 0; i < 3; i++){
v = u;
int k = v.a[i];
v.a[i] = v.a[i + 1];
v.a[i + 1] = k;
tmp = get_num(v.a);
if (vis[tmp] == 0){
v.step = u.step + 1;
mp[tmp] = v.step;
vis[tmp] = 2;
q.push(v);
}
else if (vis[tmp] == 1)
return u.step + mp[tmp] + 1;
}
}
}
}
int main()
{
int t;
cin >> t;
while (t--){
string s1, s2;
cin >> s1 >> s2;
for (int i = 0; i < 4; i++)
s.a[i] = s1[i] - '0';
for (int i = 0; i < 4; i++)
e.a[i] = s2[i] - '0';
s.step = 0;
e.step = 0;
cout<
H-Eight
整体思路:需要引入新知识点康托展开,A*算法,曼哈顿距离
康拓展开+A*算法(h:曼哈顿距离估价,g:步数)+优先队列+利用逆序数判断是否有解
#include
#include
#include
#include
using namespace std;
struct Node{
int mp[3][3];
int x, y;
int h, g; //h:距目标还有多远 g:走了多少步
int hash; //此时数码序列在整个全排列中的次序,即hash值
bool operator < (const Node A)const { //重载 <
if (A.h != h) return A.h < h;
else return A.g < g;
}
bool check(){ //检查交换是否合法
if (x >= 0 && x < 3 && y >= 0 && y < 3)
return true;
return false;
}
}u, v;
int vis[362880+10];//记录交换方式
int pre[362880+10];//记录前一个数码序列的hash值
int dir[4][2] = { {0,1},{0,-1},{1,0},{-1,0} };
int f[] = { 1,1,2,6,24,120,720,5040,40320,362880 };
int get_hash(Node temp)//康托展开,计算数列的hash值
{
int a[9], k = 0, count = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
a[k++] = temp.mp[i][j]; //化为一行
for (int i = 0; i < 9; i++){
int sum = 0;
for (int j = i + 1; j < 9; j++)
if (a[i] > a[j]) sum++;
count += sum * f[9 - i - 1];
}
return count + 1;
}
int get_h(Node temp) //估价函数 ,每个数字到目标位置的距离,曼哈顿距离
{
int count = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (temp.mp[i][j])
count += abs(i - (temp.mp[i][j] - 1) / 3) + abs(j - (temp.mp[i][j] - 1) % 3);
return count;
}
bool judge(Node temp) //判断是否有解
{
int a[9], k = 0, count = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
a[k++] = temp.mp[i][j];
for (int i = 0; i < 9; i++)
for (int j = i + 1; j < 9; j++)
if (a[i] && a[j] && a[i] > a[j])
count++;
return count & 1;
}
void print()
{
string str;
str.clear();
int start = 46234;
while (pre[start] != -1){
if (vis[start] == 0) str += 'r';
else if (vis[start] == 1) str += 'l';
else if (vis[start] == 2) str += 'd';
else if (vis[start] == 3) str += 'u';
start = pre[start];
}
for (int i = str.size() - 1; i >= 0; i--) //反向输出
cout << str[i];
cout << '\n';
}
void bfs()
{
memset(vis, -1, sizeof(vis));
memset(pre, -1, sizeof(pre));
priority_queue q; //优先队列
q.push(u);
vis[u.hash] = -2;
while (!q.empty()){
u = q.top();
q.pop();
for (int i = 0; i < 4; i++){
v = u;
v.x += dir[i][0];
v.y += dir[i][1];
if (v.check()){
swap(v.mp[v.x][v.y], v.mp[u.x][u.y]);
v.hash = get_hash(v);
if (vis[v.hash] == -1){
v.h = get_h(v);
v.g++;
vis[v.hash] = i; //步骤记录
pre[v.hash] = u.hash;
q.push(v);
}
}
if (v.hash == 46234){
print(); return;
}
}
}
}
int main()
{
char ch[50];
while (cin >> ch[0]){
for (int i = 1; i < 9; i++)
cin >> ch[i];
for (int i = 0; i < 3; i++) //行
for (int j = 0; j < 3; j++) //列
if (ch[i * 3 + j] == 'x') {
u.mp[i][j] = 0, u.x = i, u.y = j; u.g = 0;
}
else
u.mp[i][j] = ch[i * 3 + j] - '0';
u.h = get_h(u), u.hash = get_hash(u);
if (u.hash == 46234){ //处理一开始就是期待值的情况
cout << '\n';
continue;
}
if (!judge(u))
bfs();
else cout << "unsolvable" << endl;
}
}
答辩总结
1.没有落实到书上
2.对知识点没有理解透彻
3.亲自上手敲代码的经验太少
4.上台表现太过紧张
5.花Java学习时间太少