蓝桥杯每日一题
1.复习并查集和连通块中点的数量
2.奶酪(两种解法)
3.格子游戏
以下是部分题目的代码
//奶酪
//解法一(并查集)
typedef long long ll;//注意要用long long类型
const ll N = 1010;
ll t, n, h, r;
ll ne[N];
struct P
{
ll x, y, z;
}p[N];
ll find(ll x)
{
if (ne[x] != x)
ne[x] = find(ne[x]);
return ne[x];
}
bool is_llersect(ll i, ll j)
{
ll dist = (p[i].x - p[j].x) * (p[i].x - p[j].x) + (p[i].y - p[j].y) * (p[i].y - p[j].y) + (p[i].z - p[j].z) * (p[i].z - p[j].z);
if (dist <= r * r * 4) return true;//取等
return false;
}
bool check()
{
for (ll i = 1; i <= n; i++)
{
for (ll j = i + 1; j <= n; j++)
{
if (p[i].z + r < p[j].z - r) break;//显然j后面的不可能与i相交,break
if (is_llersect(i, j))
{
ll pa = find(i), pb = find(j);
if(pa!=pb) ne[pa] = pb;
}
}
}
for (ll i = 1; i <= n; i++)//遍历z小且接触下表面的洞
{
if (p[i].z - r <= 0)
for (ll j = n; j >= i; j--)//遍历z大的洞且接触上表面的洞,注意j>=i,即考虑一个洞即可洞穿整个奶酪的情况
if (p[j].z + r >= h && find(i) == find(j)) return true;
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin >> t;
while (t--)
{
cin >> n >> h >> r;
for (ll i = 1; i <= n; i++) ne[i] = i;//每次都要初始化
for (ll i = 1; i <= n; i++)
{
ll x, y, z; cin >> x >> y >> z;
p[i] = { x,y,z };
}
//排序
sort(p + 1, p + n + 1, [&](P a, P b) {
return a.z < b.z;
});
if (check()) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
//奶酪
//解法二(BFS)
typedef long long ll;//注意要用long long类型
const ll N = 1010;
ll t, n, h, r, cur_h;
bool st[N];
struct P
{
ll x, y, z;
}p[N];
bool is_intersect(ll i, ll j)
{
ll dist = (p[i].x - p[j].x) * (p[i].x - p[j].x) + (p[i].y - p[j].y) * (p[i].y - p[j].y) + (p[i].z - p[j].z) * (p[i].z - p[j].z);
if (dist <= r * r * 4) return true;//取等
return false;
}
bool check()
{
if (p[1].z - r > 0) return false;//连第一个都不符合要求则退出
queue<int> q;
//注意不只是弹入第一个!
for (int i = 1; i <= n; i++)
{
if (p[i].z - r > 0) break;
q.push(i);
st[i] = true;
}
while (q.size())
{
int cur = q.front(); q.pop();
cur_h = p[cur].z + r;
if (cur_h >= h) return true;//如果当前高度已经达到h,则可退出
for (int i = cur + 1; i <= n; i++)
{
if (p[cur].z + r < p[i].z - r) break;//显然i之后的不符合要求,马上退出
if (st[i]) continue;//标记,减少重复入队
if (is_intersect(cur, i))//相交的则加入队列
{
q.push(i);
st[i] = true;
}
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin >> t;
while (t--)
{
cin >> n >> h >> r;
memset(st, false, sizeof st);
for (ll i = 1; i <= n; i++)
{
ll x, y, z; cin >> x >> y >> z;
p[i] = { x,y,z };
}
//排序
sort(p + 1, p + n + 1, [&](P a, P b) {
return a.z < b.z;
});
if (check()) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
//格子游戏
//思路:构成封闭圈的最后一条连线的两个点在同一个连通块
const int N = 210;
int n, m, p[N * N];
int find(int x)
{
if (p[x] != x)
p[x] = find(p[x]);
return p[x];
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1; i <= n * n; i++) p[i] = i;
int mark = 0;
for (int i = 1; i <= m; i++)
{
int x1, y1; cin >> x1 >> y1;
int x2 = 0, y2 = 0;
string op; cin >> op;
if (op == "D") x2 = x1 + 1, y2 = y1;
else if (op == "R") x2 = x1, y2 = y1 + 1;
int a = (x1 - 1) * n + y1, b = (x2 - 1) * n + y2;
int pa = find(a), pb = find(b);
if (pa == pb)
{
mark = i;
break;
}
else p[pa] = pb;
}
if (mark) cout << mark << endl;
else cout << "draw" << endl;
return 0;
}