再戦を設定し、問題に2004年にNOIPユニバーサルソリューション

トピックカバーアルゴリズム:

  • 不幸Jinjin:質問をはじめ、
  • ピーナッツピッキング:貪欲。
  • FBIの木:再帰、DPと需要の間隔;
  • 火星:アナログ。

不幸Jinjin

トピックリンク:
シンプル列挙。
再びトラバーサル、検索\([I] + B [I] \) 座標できる最大。
次のようにコードは次のとおりです。

#include <bits/stdc++.h>
using namespace std;
int a[8], b[8], id;
int main() {
    for (int i = 1; i <= 7; i ++) {
        cin >> a[i] >> b[i];
        if (a[i] + b[i] > 8 && (!id || a[i]+b[i] > a[id]+b[id]))
            id = i;
    }
    cout << id << endl;
    return 0;
}

ピーナッツピッキング

トピックリンク:https://www.luogu.org/problem/P1086
貪欲。
HERE条件は、「これらの異なるにおける仮定ピーナッツ植物の数」であるので、我々は直接降順でピーナッツの数に応じてすることができますが、また彼の行番号、列番号の各要素を記録する必要があり、ピーナッツの数。
第二の路側からソートされた要素に\(0 \) からの座標と仮定植物それぞれ(0 \)\の時間が決定された開始)、それは最初に\(0 \)植物各ライン番号、ピッキング良いセクション\(N-1 \)植物が街路樹に戻した後の時間、つまり、決定することができるされている\(1 \)を
そしてより\(Iは\)植物の各\(I + 1 \)木時間の植物は、トランジションの2つの方法があります。

  1. \(私は\)植物それぞれが直接最初の到達\(I + 1 \)それぞれの時間を選ぶが費やされている植物X_I-X_ {I | \( + 1} | + | Y_I + Y_ {I + 1を} |。+ 1 \) ここでは、\(X_I \)を表す\を(私は\)植物それぞれの行番号、\(Y_I \)を表す\を(私は\)植物の各列番号、\(| | \)を表し\(\)の絶対値)。
  2. \(Iは\) 植物、最初ストリートから来る各ジャンプ道路の裏面\(I + 1 \)植物それぞれ、使用済みピッキング時間が\(X_I + X_ {iは、+ 1} + 1 \) 。

そして、私は2つの小さい方を取る必要があります。\(\ RIGHTARROW \)これは貪欲この質問の本質です。
その後、私は私がもっと欲しいことが判明し、この問題が想定しているその道路に戻りませんピーナッツを取る過程でサル、被写体がモバイル道路の支出を言わなかったので、途中の道路への復帰の可能性について考えていくつかの学生時間は、その道のうち、よりがあるかもしれませんし、その後ピーナッツを迎えに行きます。
したがって、我々は最初の2つの条件が〜することができ考えます

限られた時間の後、あります\(Kは\) 我々は、それだけに限られた時間内に、上述した実施の形態をオフすることができますどのように多くの行を決定する必要があります。

次のようにコードは次のとおりです。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 440;
struct Node {
    int x, y, z;
} a[maxn];
int n, m, k, cnt, dis, ans;
bool cmp(Node a, Node b) {
    return a.z > b.z;
}
int main() {
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= m; j ++) {
            a[cnt].x = i;
            a[cnt].y = j;
            cin >> a[cnt].z;
            if (a[cnt].z) cnt ++;
        }
    }
    sort(a, a+cnt, cmp);
    for (int i = 0; i < cnt; i ++) {
        if (!i) dis += a[i].x + 1;
        // else dis += min( abs(a[i].x-a[i-1].x) + abs(a[i].y-a[i-1].y), a[i-1].x + a[i].x ) + 1;
        else dis += abs(a[i].x - a[i-1].x) + abs(a[i].y - a[i-1].y) + 1;
        if (dis + a[i].x <= k) ans += a[i].z;
    }
    cout << ans << endl;
    return 0;
}

FBIツリー

トピックリンク:https://www.luogu.org/problem/P1087
この質問は、再帰的トラバーサル範囲を使用することです。
私は間隔と、その後再帰的に、またはテンプレートツリーラインのセットを実装するために、動的プログラミングを使用することができます。
以下のように、本明細書中で使用される動的プログラミング+再帰の使用のみを説明します。

#include <bits/stdc++.h>
using namespace std;
const int maxn = (1<<10|1);
char ch[maxn+10];
int tree[maxn<<2], n, m, sum[maxn];
void solve(int L, int R, int n) {
    if (n) {
        solve(L, L+(1<<(n-1))-1, n-1);
        solve(L+(1<<(n-1)), R, n-1);
    }
    int tmp = sum[R] - sum[L-1];
    if (tmp == (1<<n)) putchar('I');
    else if (!tmp) putchar('B');
    else putchar('F');
}
int main() {
    scanf("%d%s", &n, ch+1);
    m = (1<<n);
    for (int i = 1; i <= m; i ++)
        sum[i] = sum[i-1] + (ch[i] == '1');
    solve(1, m, n);
    return 0;
}

火星

トピックリンク:https://www.luogu.org/problem/P1088
この質問は、完全な配列をシミュレートし、アナログです。
STLが提供するしかし、next_permutation機能を、私はただの使用を作ります。
次のようにコードは次のとおりです。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
int n, m, a[maxn];
int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i ++) cin >> a[i];
    while (m --) next_permutation(a, a+n);
    for (int i = 0; i < n; i ++) {
        if (i) putchar(' ');
        cout << a[i];
    }
    cout << endl;
    return 0;
}

著者:zifeiy

おすすめ

転載: www.cnblogs.com/codedecision/p/11717543.html