这一次考试……嗯爆零了……
题目虽然有一定的难度,但不至于拿不到分……
具体的总结就不说了,直接放改错的代码
考试目录
种植仙人掌
DP + 前缀和维护
用一个二维数组f[i][j]表示以(0,0)及(i,j)为两定点的矩形中树的棵数
对于每一个小矩形中讨论满足棵树的边长的最大值
以上两个步骤均由DP来实现
#include <iostream>
#include <cstdio>
#define L 1000 + 100
using namespace std;
int a[L][L], f[L][L];
int n, m, t, ans = 0;
char x;
int max(int a, int b) {
return a > b ? a : b;
}
int min(int a, int b) {
return a < b ? a : b;
}
int main() {
//freopen("cacti.in", "r", stdin);
//freopen("cacti.out", "w", stdout);
scanf("%d %d %d", &n, &m, &t);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
cin >> x;
if (x == '.') a[i][j] = 0;
if (x == 'T') a[i][j] = 1;
f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + a[i][j];
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
for (int k = ans; k <= min(i, j); ++k)
if (f[i][j] - f[i - k][j] - f[i][j - k] + f[i - k][j - k] <= t)
ans = max(ans, k);
printf("%d\n", ans * ans);
return 0;
}
网络攻击
此题可参考2008曹钦翔的论文
我贴的代码参考了很多标程,各处的定义不一样,仔细识别各变量的含义
先来明确一下我的代码中的各个变量(样例见上图)
d[i]表示第i个点的深度
q[i]存放按dfs序排列的各个点
p[i]表示i指向其父节点的边的个数
l[i][j]表示点i的所有儿子节点到深度为j的节点的边数(dfs中持续更新的)
s[i]表示i的儿子节点直接与i的父亲节点相连的边数
t[i]表示与i相连的父节点中深度最大的一个
r表示当前点的时间戳(pos),后因递归影响也表示当前q中的元素个数
ans1表示桥(即断开就能是图一分为二的边)的数量
ans2即为要输出的答案,在dfs中是在找非桥边中满足断开为两个图的边数解题思路
因为图中的边分为桥边和非桥边,所以在dfs中分别进行查询
- 桥边:如果存在一个点到其父亲仅有一条直接相连的边(即s[i] == 1),则存在一条桥边–>ans1++;
- 非桥边:(I)若s[i] == 2,由定义显然ans2++; (II)对于i的子节点若存在与i点直连父节点的边数相等并且其父节点深度小于i深度的点,显然存在一条满足情况的边,ans2++; (III)对于任意点若其与父节点的连边不止一条,显然存在重边现象,所以(I)步骤后(II)步骤时,都需考虑p[i]是否为1,只有p[i]==1时才能继续进行操作
- 得出桥边ans1、非桥边ans2后显然最终结果为ans2 + (m - ans1) * ans1 + ans1 * (ans1 - 1) / 2;(手玩找规律吧……挺简单的)
- 详细的算法证明可参考2008曹钦翔的论文,csdn上可下载
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define M 200001
#define N 2001
using namespace std;
long long ans2 = 0;
int n, m, ans1 = 0;
int a, b, r, d[N], e[M], nxt[M], head[N], q[N], p[N], l[N][N], s[N], t[N];
inline void add(int k, int a, int b) {
e[k] = b;
nxt[k] = head[a];
head[a] = k;
}
inline void dfs (int k, int fa) {
int pos = ++r;
q[r] = k, p[k] = 0, d[k] = d[fa] + 1;
for (int x = head[k]; x; x = nxt[x])
if (e[x] == fa) p[k]++;
else if (d[e[x]] && d[e[x]] < d[k]) l[k][d[e[x]]]++;
else if (!d[e[x]]) {
dfs(e[x], k);
for (int i = 1; i < d[e[x]]; ++i) l[k][i] += l[e[x]][i];
}
s[k] = p[k];
for (int i = 1; i < d[k]; ++i)
if (l[k][i])
s[k] += l[k][i], t[k] = i;
if (s[k] == 1) ans1++;
else {
if (s[k] == 2) ans2++;
if (p[k] > 1) return ;
for (int i = pos + 1; i <= r; ++i)
if (p[q[i]] == 1 && s[k] == s[q[i]] && t[q[i]] < d[k])
ans2++;
}
}
int main() {
freopen("networkattack.in", "r", stdin);
freopen("networkattack.out", "w", stdout);
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++i) {
scanf("%d %d", &a, &b);
if (a != b) {
add(i, a, b);
add(i + m, b, a);
}
}
dfs(1, 0);
ans2 += (m - ans1) * ans1 + ans1 * (ans1 - 1) / 2;
printf ("%lld\n", ans2);
return 0;
}
旅行者
这道题数据有点诡异,网上AC的代码一直T
放上一个自己测是50分的代码网址
http://www.cnblogs.com/abclzr/p/5862592.html
以后有时间再来处理这道题吧…………