C - Shapes
题意:
给定两个图, S S S和 T T T,’#'代表图案, ‘ . ’ ‘.’ ‘.’代表空,整幅图是 N ✖ N N✖N N✖N的大小,现在问你,能否旋转90°和平移的操作(操作数不限),来把S图中的图案,变成T中的图案
思路:
找到S图和T图中,图案的最左端、右端、上端、下端的坐标,上下左右坐标之外的地方说明都是空地,不用管,此时,此时,把新图(坐标是最左端右端上端下端之中的图),通过旋转,会有4种情况,旋转0,90,180,270,把旋转出来的图,存下来,看T图中是否有上述4种情况之一的图,可以小优化一下,如果找出来的图,一个是正方形另一个不是,那就直接不行。
#include <bits/stdc++.h>
using namespace std;
const int N = 210;
#define inf 0x3f3f3f3f
char S[N][N], T[N][N];
int n;
int u, l, r, d;
int U, L, R, D;
void change() {
map<string, int> m;
int f1, f2, f3, f4;
f1 = f2 = f3 = f4 = 1;
string s;
for (int i = u; i <= d; i++) {
for (int j = l; j <= r; j++) {
s.push_back(S[i][j]);
}
}
m[s]++;
s.clear();
for (int i = l; i <= r; i++) {
for (int j = d; j >= u; j--) {
s.push_back(S[j][i]);
}
}
m[s]++;
s.clear();
for (int i = r; i >= l; i--) {
for (int j = u; j <= d; j++) {
s.push_back(S[j][i]);
}
}
m[s]++;
s.clear();
for (int i = d; i >= u; i--) {
for (int j = r; j >= l; j--) {
s.push_back(S[i][j]);
}
}
m[s]++;
s.clear();
for (int i = U; i <= D; i++) {
for (int j = L; j <= R; j++) {
s.push_back(T[i][j]);
}
}
if (m[s] >= 1) {
puts("Yes");
} else
puts("No");
return;
}
int main() {
cin >> n;
u = U = l = L = inf;
r = d = R = D = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> S[i][j];
if (S[i][j] == '#') {
u = min(u, i);
d = max(d, i);
l = min(l, j);
r = max(r, j);
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> T[i][j];
if (T[i][j] == '#') {
U = min(U, i);
D = max(D, i);
L = min(L, j);
R = max(R, j);
}
}
}
//一方为正方形,另一方不是
if (d - u == R - l && r - l != D - U && r - l == R - L && d - u != D - U) {
puts("No");
return 0;
}
change();
return 0;
}
D - Rectangles
题意:
给 n n n个点的坐标,让你找四个坐标,组成一个矩形,问有多少个矩形的边与 x x x轴,或 y y y轴平行。
思路:
直接枚举矩形的右上端点(
x
1
,
y
1
x_1,y_1
x1,y1)和左下端点(
x
2
,
y
2
x_2,y_2
x2,y2),看是否右两个点的坐标(
x
1
,
y
2
x_1,y_2
x1,y2)(
x
2
,
y
1
x_2,y_1
x2,y1)来组成一个符合题意的矩形。
找(
x
1
,
y
2
x_1,y_2
x1,y2)(
x
2
,
y
1
x_2,y_1
x2,y1)这两个坐标的方法,可以用binary_search函数来二分找,也可以用桶提前把坐标存下来,来找。
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 2020;
#define x first
#define y second
int n;
int main() {
scanf("%d", &n);
vector<PII> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i].x >> a[i].y;
}
sort(a.begin(), a.end());
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (a[i].x < a[j].x && a[i].y < a[j].y) {
if (binary_search(a.begin(), a.end(),
make_pair(a[i].x, a[j].y)) &&
binary_search(a.begin(), a.end(),
make_pair(a[j].x, a[i].y))) {
res++;
}
}
}
}
printf("%d\n", res);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct node {
int x, y;
} e[N];
map<int, map<int, int>> vis;
int n;
bool cmp(node a, node b) {
if (a.x != b.x) return a.x < b.x;
return a.y < b.y;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> e[i].x >> e[i].y;
vis[e[i].x][e[i].y] = 1;
}
sort(e + 1, e + n + 1, cmp);
int res = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (e[i].x < e[j].x && e[i].y < e[j].y) {
if (vis[e[i].x][e[j].y] == 1 && vis[e[j].x][e[i].y] == 1) {
res++;
}
}
}
}
cout << res << endl;
}
E - Destruction
题意:
给你一张连通图, n n n个点 m m m条边,现在让你在满足图是连通的情况下,删除一些边w,如果删除的边是正的,你将会得到+w的价值,如果删除的边是负的,你将会得到-w的价值,现在让你删除一些边,并保证图是连通的,问你能得到的最大价值。
思路:
所有边的权值和 − - −最小生成树(这个不是严格的最小生成树,所有负数边全放在生成树边中)的边权和= a n s ans ans
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, M = N * 2;
#define int long long
struct node {
int a, b;
int w;
bool operator<(const node &t) const { return w < t.w; }
} e[M];
int fa[N];
int n, m;
int find(int x) {
if (x != fa[x]) fa[x] = find(fa[x]);
return fa[x];
}
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
int sum = 0;
for (int i = 0; i < m; i++) {
int a, b, c;
scanf("%lld%lld%lld", &a, &b, &c);
e[i] = {a, b, c};
sum += c;
}
sort(e, e + m);
int res = 0;
for (int i = 0; i < m; i++) {
int a = e[i].a, b = e[i].b, c = e[i].w;
a = find(a), b = find(b);
if (a != b || (c < 0)) {
fa[a] = b;
res += c;
}
}
cout << sum - res << endl;
}
F - Blocked Roads
题意:
给你一个 n n n个点 m m m条有向边的图,边权是1,让你现在让你枚举每条边,即第 i i i条边,输出删除第 i i i边的从 1 1 1到 n n n的最短路,如果不可达,输出-1
思路:
先跑一边最短路,然后记录最短路的路径,如果删除的边不是最短路的路径,那么对最短路没有影响,否则就输出删除这条边后的最短路,时间复杂度O( N 2 l o g N N^2logN N2logN)
#include <bits/stdc++.h>
using namespace std;
const int N = 400, M = 2 * N * N;
#define inf 0x3f3f3f3f
typedef pair<int, int> PII;
int h[M], e[M], ne[M], idx;
bool vis[M];
int dis[M];
int n, m;
map<int, map<int, int> > st;
PII q[M];
void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
int pre[M];
void dijkstra(int x, int y) {
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[1] = 0;
priority_queue<PII, vector<PII>, greater<PII> > q;
q.push({0, 1});
while (q.size()) {
// cout<<dis[n]<<endl;
auto t = q.top();
q.pop();
int now = t.second, distance = t.first;
if (vis[now]) continue;
vis[now] = 1;
for (int i = h[now]; ~i; i = ne[i]) {
int j = e[i];
if (now == x && j == y) continue;
if (dis[j] > distance + 1) {
dis[j] = distance + 1;
q.push({dis[j], j});
pre[j] = now;
}
}
}
}
int main() {
memset(h, -1, sizeof(h));
cin >> n >> m;
for (int i = 0; i < m; i++) {
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
q[i] = {a, b};
}
dijkstra(-1, -1);
int now = n;
while (pre[now]) {
st[pre[now]][now] = 1;
now = pre[now];
}
int res;
if (dis[n] >= inf) {
res = -1;
} else
res = dis[n];
for (int i = 0; i < m; i++) {
if (st[q[i].first][q[i].second] == 1) {
dijkstra(q[i].first, q[i].second);
if (dis[n] >= inf)
puts("-1");
else
cout << dis[n] << endl;
} else
cout << res << endl;
}
return 0;
}
To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激