玉 | Aizu Online Judge

シンプルな深さ優先探索。全通り試してOK。

int tama[11];
 
bool solve(int i, int n) {
    if (i == 10) {
        int al=-1, bl=-1;
        for (int j = 0; j < 10; j++) {
            if ((1<<j)&n) {
                if (al < tama[j])
                    al=tama[j];
                else
                    return false;
            } else {
                if (bl < tama[j])
                    bl=tama[j];
                else
                    return false;
            }
        }
        return true;
    }
    bool a = solve(i+1, n|(1<<i));
    bool b = solve(i+1, n);
    return a || b;
}
 
int main() {
    while (1) {
        int N; cin >> N;
        for(int i = 0; i < N; i++) {
            for (int j = 0; j < 10; j++) {
                cin >> tama[j];
            }
            if (solve(0, 0)) {
                cout << "YES" << endl;
            } else {
                cout << "NO" << endl;
            }
        }
        break;
    }
    return 0;
}

SRM 659 Div1 ApplesAndOrangesEasy

ほぼ1ヶ月ぶりの更新か...。久しぶりすぎてTopCoderの提出法忘れていた...。

BITかなと一瞬思ったが、リンゴを1とおくと簡単にサブリストのリンゴの数を計算できるので、事前に合計を計算してから単純に左端、右端を引いたり足したりしていくことにした。

class ApplesAndOrangesEasy {
public:
    int maximumApples(int N, int K, vector <int> info) {
        int arr[2005] = {};
        int k2 = K/2;
        for (int i : info) {
            arr[i-1]=1;
        }
        for (int i = 0; i < N; i++) {
            if (arr[i]==1)continue;
            arr[i]=1;
            int left = max(0, i-K+1);
            int right = min(N-1, i+K-1)-K+1;
            int sum = 0;
            for (int j = 0; j < K; j++) {
                sum += arr[left+j];
            }
            bool f = true;
            for (int j = left; j <= right; j++) {
                if (sum > k2){
                    f=false;
                    break;
                }
                sum -= arr[j];
                sum += arr[K+j];
            }
            if(!f)
                arr[i]=0;
        }
        int cnt =0;
        for (int i = 0; i < N; i++) {
            if (arr[i])
                cnt+=arr[i];
        }
        return cnt;
    }
};

AOJ Lupin The 4th

Lupin The 4th | Aizu Online Judge

巡回セールスマン問題。経路復元が必要。 経路復元は、それ用に配列をもう一つ用意しておいて、最短の移動順序を記録しておく。

double dp[100000][20];
int pos[100000][20];
int n;
int kura[20], d[20], sen[20];

double solve(int S, int v, int weight) {
    if (S == ((1 << n) - 1)) return dp[S][v] = 0;
    if (dp[S][v] >= 0) return dp[S][v];

    double res = 1000*1000*1000;
    for (int i = 0; i < n; i++) {
        if (!(S & (1 << i))) {
            double td = abs(d[i]-d[v]);
            double ts = 2000.0/(double)(70+weight);
            double tres = solve(S | (1 << i), i, sen[i]*20 + weight) + td/ts;
            if (res > tres) {
                res = tres;
                pos[S][v] = i;
            }
        }
    }
    return dp[S][v] = res;
}

int main() {
    cin >> n;
    for (int i = 0; i < 100000; i++) fill(dp[i], dp[i]+20, -1);
    for (int i = 0; i < n; i++) {
        cin >> kura[i] >> d[i] >> sen[i];
    }
    d[n] = 0;
    solve(0, n, 0);
    int S = 0, cur = n;
    vector<int> r;
    for (int i = 0; i < n; i++) {
        int next = pos[S][cur];
        r.push_back(next);
        S = (S | (1 << next));
        cur = next;
    }
    for (int i = 0; i < n-1; i++) cout << kura[r[i]] << ' ';
    cout << kura[r[n-1]] << endl;
    return 0;
}

Patisserie | Aizu Online Judge

Patisserie | Aizu Online Judge

巡回セールスマン問題。

dp[すでに並べたケーキの集合][最後に置いたケーキ]としてメモ化再帰で解く。

グラフはG[ケーキv][ケーキu]として、ケーキvの次にケーキuを置く時、どれほど長さが増えるかで事前に作っておく。

同じサイズのケーキじゃない限り、ちょっとめりこむのでその数値を事前に計算しておく(シンプルな算数でOK)。

ケーキを一つも置いてない状態->新たにケーキを置く状態もノードに加えておく。

入力ケースが特殊なのでC++での方法が分からずちょっと手間取った。

double dp[10000][15];
double d[15][15];
double r[13];
int n;

double solve(int S, int v) {
    if (S == ((1<<n)-1)) {
        return dp[S][v] = 0;
    }
    if (dp[S][v] >= 0) return dp[S][v];

    double res = 1000*1000*1000;
    for (int i = 0; i < n; i++) {
        if (!((1 << i) & S)) {
            double ds = d[v][i];
            res = min(res, solve(S | (1 << i), i) + ds);
        }
    }

    return dp[S][v] = res;
}

int main() {
    while (1) {
        string s;
        getline(cin, s);
        stringstream ss(s);
        if (s == "") break;
        double m; ss >> m;
        n = 0;
        for (int i = 0; i < 13; i++) {
            ss >> r[i];
            if (!r[i]) break;
            n++;
        }
        for (int i = 0; i < 10000; i++)
            for (int j = 0; j < 15; j++)
                dp[i][j] = -1;
        for (int i = 0; i < 15; i++)
            for (int j = 0; j < 15; j++)
                d[i][j] = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i == j) continue;

                if (r[i] == r[j]) {
                    d[i][j] = r[i]*2;
                    d[j][i] = r[i]*2;
                } else {
                    int a = abs(r[i] - r[j]);
                    int c = r[i] + r[j];
                    double b = sqrt(c*c-a*a);
                    d[i][j] = b + r[j] - r[i];
                    d[j][i] = b + r[i] - r[j];
                }
            }
        }
        for (int i = 0; i < n; i++) {
            d[i][n] = 0;
            d[n][i] = r[i]*2;
        }
        if (solve(0, n) <= m) {
            cout << "OK" << endl;
        } else {
            cout << "NA" << endl;
        }
    }
    return 0;
}

Russian Dolls

Russian Dolls

DP。最長増加部分列。

int main() {
    while (1) {
        vector< pair<int, int> > vp;
        int dp[205];
        int n; cin >> n; if (n == 0) break;
        for (int i = 0; i < n; i++) {
            int h, r; cin >> h >> r;
            vp.push_back(pair<int, int>(h, r));
        }
        int m; cin >> m;
        for (int i = 0; i < m; i++) {
            int h, r; cin >> h >> r;
            vp.push_back(pair<int, int>(h, r));
        }
        sort(vp.begin(), vp.end());
        for (int i = 0; i < vp.size(); i++) {
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
                if (vp[j].first < vp[i].first && vp[j].second < vp[i].second) {
                    dp[i] = max(dp[i], dp[j] + 1);
                }
            }
        }
        int res = 0;
        for (int i = 0; i < vp.size(); i++) {
            res = max(res, dp[i]);
        }
        cout << res << endl;
    }

    return 0;
}

At Boss's Expense

At Boss's Expense

一発で書けた。素数とナップザック問題。

bool dp[35][1000005];
bool pt[1000005];

int main() {
    memset(pt, 1, sizeof(pt));
    pt[0] = 0; pt[1] = 0;
    for (int i = 2; i * i < 1000005; i++) {
        if (pt[i]) {
            for (int j = i*2; j < 1000005; j+=i) {
                pt[j] = 0;
            }
        }
    }
    while (1) {
        int n, x; cin >> n >> x;
        if (n == 0 && x == 0) break;
        int v[35]; memset(v, 0, sizeof(v));
        for (int i = 0; i < n; i++) cin >> v[i];
        memset(dp, 0, sizeof(dp));
        dp[0][0] = 1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= x; j++) {
                if (j - v[i] >= 0)
                    dp[i + 1][j] |= dp[i + 1][j - v[i]];
                dp[i + 1][j] |= dp[i][j];
            }
        }
        int res = -1;
        for (int i = 2; i <= x; i++) {
            if (dp[n][i] && pt[i]) {
                res = max(res, i);
            }
        }
        if (res != -1)
            cout << res << endl;
        else
            cout << "NA" << endl;
    }

    return 0;
}

A Thief

泥棒 | Aizu Online Judge

int main() {
    int cas = 1;
    while (1) {
        int N, W;
        int v[1005], w[1005], dp[1005][1005];
        cin >> W; if (!W) break;
        cin >> N;
        for (int i = 0; i < N; i++) {
            char c;
            cin >> v[i] >> c >> w[i];
        }
        memset(dp, -1, sizeof(dp));
        dp[0][0] = 0;
        int res = 0, resw = 1000*1000*1000*2;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j <= W; j++) {
                if (j - w[i] >= 0) {
                    dp[i + 1][j] = max(dp[i][j - w[i]] + v[i], dp[i][j]);
                } else {
                    dp[i + 1][j] = dp[i][j];
                }
                if (dp[i+1][j] == -1) continue;
                if (dp[i + 1][j] > res) {
                    res = dp[i + 1][j];
                    resw = j;
                } else if (dp[i + 1][j] == res) {
                    resw = min(resw, j);
                }
            }
        }
        cout << "Case " << cas << ":" << endl;
        cout << res << endl;
        cout << resw << endl;
        cas++;
    }
    return 0;
}