1.24

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

考试目录

种植仙人掌

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
以后有时间再来处理这道题吧…………

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值