# 题目大意
有两个网格 S,T,每个网格都是 N 行 N 列
每个单元格都被涂成白 / 黑色,单元格是 .
就是白色,是 #
就是黑色
你可以进行下面两种操作任意次
- 选中 S 中的一个格子,反转颜色
- 将 S 顺时针旋转 90°
请问至少要多少次操作,才能使 S 和 T 变成一样的?
# 数据范围
- 1≤n≤100
# 题解
考虑四种旋转后,与 T 图的差异即可,需要注意的是,这四次旋转需要的 2 操作次数是不一样的
C++1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| int calDif() { int dif = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) dif += (c[i][j] != b[i][j]); return dif; }
void solve () { cin >> n; a = vector<vector<char>>(n + 1, vector<char>(n + 1)); b = vector<vector<char>>(n + 1, vector<char>(n + 1)); c = vector<vector<char>>(n + 1, vector<char>(n + 1));
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) cin >> a[i][j]; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) cin >> b[i][j];
int t[5];
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) c[i][j] = a[i][j]; t[0] = calDif();
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) c[i][j] = a[n - j + 1][i]; t[1] = calDif();
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) c[i][j] = a[n - i + 1][n - j + 1]; t[2] = calDif();
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) c[i][j] = a[j][n - i + 1]; t[3] = calDif();
int res = 1e18; for (int i = 0; i < 4; i++) res = min(res, i + t[i]); cout << res << '\n'; }
|
# 题目大意
给你一个 N 个点 M 条边的无向图,请你判断这个图是否是循环图
循环图的定义
对于一个图,若存在 (1,2,...,N) 的一个排列 (v1,v2,...,vN) 满足
- 对于每个i=1,2,...,N−1,vi 和 vi+1 之间有一条边
- v1 和 vN 直接有一条边
- 不存在其他边
那么就称这个图为循环图
# 数据范围
- 3≤N≤2×105
- 0≤M≤2×105
# 题解
3. 不存在其他边
这个条件,要求此时 n == m
如果是一个环图,那么每个点一定只有两个方向能走,也就是说, g[i].size()==0
;并且任意从一点开始深搜,如果能搜到 n 个点(在 n == m
的前提条件下),那么一定是个环图
C++1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| int n, m, cnt = 1; vector<int> g[N]; vector<bool> st(N);
void dfs(int u) { for (int t : g[u]) if (!st[t]) st[t] = 1, cnt++, dfs(t); }
void solve () { cin >> n >> m;
for (int i = 1, a, b; i <= m; i++) { cin >> a >> b; g[a].push_back(b), g[b].push_back(a); }
if (m != n) { cout << "No\n"; return; } for (int i = 1; i <= n; i++) if (g[i].size() != 2) { cout << "No\n"; return; }
st[1] = 1, dfs(1);
cout << (cnt == n ? "Yes" : "No") << '\n'; }
|
# 题目大意
有 N 个动物园,第 i 个动物园的门票是 Ci 元
你喜欢 M 种动物,1,2,...,M,第 i 种动物在 Ki 个动物园中被展出,分别是 Ai,1,...,Ai,Ki
看完你喜欢的所有动物(每种看两次),最少要花多少钱
# 数据范围
- 1≤N≤10
- 1≤M≤100
- 0≤ci≤109
# 题解
观察数据范围,可以看到 N 很小,考虑暴力 DFS
c++1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| int n, m, cost = 1e18; vector<int> c, cnt; vector<int> g[N];
void dfs(int u, int spend) { if (u == n + 1) { for (int i = 1; i <= m; i++) if (cnt[i] < 2) return; cost = min(cost, spend); return; }
for (int t : g[u]) cnt[t]++; dfs(u + 1, spend + c[u]);
for (int t : g[u]) cnt[t]++; dfs(u + 1, spend + 2 * c[u]);
for (int t : g[u]) cnt[t] -= 2; dfs(u + 1, spend); }
void solve () { cin >> n >> m; c = vector<int>(n + 1), cnt = vector<int>(m + 1);
for (int i = 1; i <= n; i++) cin >> c[i]; for (int i = 1, k, a; i <= m; i++) { cin >> k;
while (k--) { cin >> a; g[a].push_back(i); } } dfs(1, 0); cout << cost << '\n'; }
|
# 题目大意
你有 N 个茶碗,它们排成一排,编号为 0,1,...,N−1
对于 1 号碗和其右边的碗,第 i 个碗上写着 Ci,里面装了 Ai 个豆子,0 号碗没写数字,没装豆子
你将执行以下操作若干次
- 选择一个写了数字的、有豆子的碗,拿走若干个豆子
- 把拿出的豆子任意放入 i−Ci,i−Ci+1,...,i−1 号碗里
请问,将所有豆子放入 0 号碗,最少需要操作多少次?
# 数据范围
- 1≤N≤2000
# 题解
这题考虑贪心写法
- 尽可能把豆子往左送 →
j - c[j] < idx - c[idx]
- 如果
i - c[i] -> i - 1
内,有 ai=0 的点,那么往这个有豆子的点上送
C++1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| void solve () { cin >> n; vector<int> c(n + 1), a(n + 1);
for (int i = 1; i <= n - 1; i++) cin >> c[i]; for (int i = 1; i <= n - 1; i++) cin >> a[i];
int res = 0;
for (int i = n - 1; i >= 1; i--) { if (a[i]) { res++;
bool flag = true; int t = -1;
for (int idx = i - c[i]; idx <= i - 1; idx++) { if (a[idx]) { flag = 0; break; }
if (t == -1 || idx - c[idx] < t - c[t]) t = idx; }
if (flag) a[t] += a[i]; } }
cout << res << '\n'; }
|