日常訓練 20170628 神奇的玩具

題意簡述:n 個玩具,m 家店買這些玩具,只能進 k 個店,要每種玩具各買一份並且代價最小,求最小總價格。
數據範圍: 1m40 ,1n100 ,0pi,qi107
題解: 一開始想暴搜,結果看周圍人都紛紛網絡流,我思索了一下,腦補了一個看起來很對的費用流,對於每個店建一個流量爲 1 費用爲一個很大的數的邊,然後再建一條流量 n 費用爲 0 的邊,強制先流哪條費用大的邊,退流時後退那條邊,結果死循環了,DJY大佬說費用函數斜率要非負,我實在是太蠢了。
   正解居然真的是暴搜,姿勢不同得分也很不同,因爲 n 比較大,所以要搜 m ,而且搜索時加一些必要性剪枝比如一件商品在前一個店沒買在這個店肯定要買,再加上最優性剪枝(要加估價不然會多剪到最優解)。

#include<bits/stdc++.h>
typedef long long ll;
const int N = 105;
struct rec{
    int v, _x, _v, next;
} mp[N * 2];
int n, m, k, first[N], s;
ll f[N], ans;
void ins(int x, int v, int _x, int _v) {
    mp[++s] = (rec) {v, _x, _v, first[x]};
    first[x] = s;
}
void dfs(int dep, int pick, ll S, ll now) {
    if (now - f[dep] > ans) return;
    if (dep == m) {if (now < ans) ans = now; return;}
    bool can_not_choose = 1;
    for (int t = first[dep]; t; t = mp[t].next)
        if (mp[t]._x <= dep && !(S & (1ll << mp[t]._x))) {can_not_choose = 0; break;}
    if (can_not_choose) dfs(dep + 1, pick, S, now);
    if (pick == k) return;
    for (int t = first[dep]; t; t = mp[t].next) {
        if (mp[t]._x >= dep || !(S & (1ll << mp[t]._x)))
            now += mp[t].v;
        else
            if (mp[t].v < mp[t]._v)
                now -= mp[t]._v - mp[t].v;
            else;
    }
    dfs(dep + 1, pick + 1, S ^ (1ll << dep), now);
}
int main() {
    freopen("toy.in", "r", stdin);
    freopen("toy.out", "w", stdout);
    scanf("%d%d%d", &n, &m, &k);
    int a, p, b, q;
    for (int i = 1; i <= n; i++) {
        scanf("%d%d%d%d", &a, &p, &b, &q); a--, b--;
        if (a == b) p = q = std::min(p, q);
        ins(a, p, b, q); if (a != b) ins(b, q, a, p);
        if (a > b) std::swap(a, b), std::swap(p, q);
        if (q < p) for (int i = a; i <= b; i++) f[i] += p - q;
    }
    ans = 1e15;
    dfs(0, 0, 0, 0);
    if (ans == (ll)1e15)
        printf("-1\n");
    else
        printf("%lld\n", ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章