1.24

来源:互联网 发布:wine下载 ubuntu 编辑:程序博客网 时间:2024/06/03 13:45

这一次考试……嗯爆零了……
题目虽然有一定的难度,但不至于拿不到分……
具体的总结就不说了,直接放改错的代码

考试目录

  • 考试目录
    • 种植仙人掌
    • 网络攻击
    • 旅行者

种植仙人掌

DP + 前缀和维护
用一个二维数组f[i][j]表示以(0,0)及(i,j)为两定点的矩形中树的棵数
对于每一个小矩形中讨论满足棵树的边长的最大值
以上两个步骤均由DP来实现

#include <iostream>#include <cstdio>#define L 1000 + 100using 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 2001using 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
以后有时间再来处理这道题吧…………

0 0
原创粉丝点击