Chaos Slover 补档计划 - 01分数规划

2015.11.28 18:32 Sat| 3 visits oi_2016| ChaosSlover补档计划| Text

01 规划问题

就是求这种东西

设答案为 T,然后把分数线下面的东西乘过去,再减回去。(这种表述好像很抽象?)这样就得到了

然后我们要求的就是使得左面的式子恰好等于 0 的那个 T,这个过程满足二分条件。

其实就是一个二分答案嘛!

POJ2976 Dropping tests

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <bits/stdc++.h>
using namespace std;

#define N 5005

int n, k, a[N], b[N];
double t[N];

double check(double mid)
{
    for (int i = 1; i <= n; ++i)
        t[i] = a[i] - mid * b[i];
    sort(t + 1, t + n + 1);
    double re = 0;
    for (int i = n; i > k; --i)
        re += t[i];
    return re;
}

int main()
{
    while (cin >> n >> k, n)
    {
        for (int i = 1; i <= n; ++i) cin >> a[i];
        for (int i = 1; i <= n; ++i) cin >> b[i];
        double l = 0, r = 1;
        while (r - l > 0.00001)
        {
            double mid = (l + r) / 2;
            if (check(mid) > 0) l = mid;
            else r = mid;
        }
        cout << fixed << setprecision(0) << r * 100 << endl;
    }
    return 0;
}

POJ2728 Desert King

终于又会写 Prim 了啊……我从来没有纠结过输出是 "%f" 还是 "%lf" 233。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <bits/stdc++.h>
using namespace std;

#define sqr(x) ((x)*(x))
#define N 1005
#define inf 1e10

int n;
double dist[N][N], val[N][N], cost[N][N];
double d[N]; bool v[N];

struct point
{
    int x, y, z;
    void read() { cin >> x >> y >> z; }
} p[N];

inline double length(point p1, point p2)
{
    return sqrt(sqr(p1.x - p2.x) + sqr(p1.y - p2.y));
}

inline double height(point p1, point p2)
{
    return fabs(p1.z - p2.z);
}

double prim()
{
    double re = 0;
    memset(v, 0, sizeof v);
    v[1] = true;
    for (int i = 1; i <= n; ++i)
        d[i] = dist[1][i];
    for (int i = 1; i < n; ++i)
    {
        int x = 0; double now = inf;
        for (int j = 1; j <= n; ++j)
            if (!v[j] && d[j] < now)
                x = j, now = d[j];
        re += d[x]; v[x] = true;
        for (int j = 1; j <= n; ++j)
            if (!v[j])
                d[j] = min(d[j], dist[x][j]);
    }
    return re;
}

int main()
{
    while (cin >> n, n)
    {
        for (int i = 1; i <= n; ++i)
            p[i].read();
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                val[i][j] = length(p[i], p[j]),
                cost[i][j] = height(p[i], p[j]);
        double s1 = 0, s2 = 0;
        for (int i = 2; i <= n; ++i)
            s1 += val[i - 1][i], s2 += cost[i - 1][i];
        double l = 0, r = s2 / s1;
        while (r - l > 1e-5)
        {
            double mid = (l + r) / 2;
            for (int i = 1; i <= n; ++i)
                for (int j = 1; j <= n; ++j)
                    dist[i][j] = cost[i][j] - mid * val[i][j];
            if (prim() < 0) r = mid;
            else l = mid;
        }
        cout << fixed << setprecision(3) << l << endl;
    }
    return 0;
}

POJ3621 Sightseeing Cows

由于显然最优解中每条边最多经过一次,所以可以把点权放到边权上。二分答案之后判断图中是否存在正权环吧!去吧,SPFA!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <bits/stdc++.h>
using namespace std;

#define N 1005
#define M 5005
#define inf 1e10

int n, m, v[N], c[N], head[N];
double f[N], d[N];
vector<int> b;
queue<int> q;

inline int read()
{
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

struct graph
{
    int next, to, val;
    graph() {}
    graph(int _next, int _to, int _val)
    : next(_next), to(_to), val(_val) {}
} edge[M];

inline void add(int x, int y, int z)
{
    static int cnt = 0;
    edge[++cnt] = graph(head[x], y, z);
    head[x] = cnt;
}

bool spfa(int s, double t)
{
    memset(v, 0, sizeof v);
    memset(c, 0, sizeof c);
    for (int i = 1; i <= n; ++i)
        d[i] = -inf;
    while (!q.empty()) q.pop();
    d[s] = c[s] = 0; v[s] = 1; q.push(s);
    while (!q.empty())
    {
        int x = q.front(); q.pop(); v[x] = 0;
        // cout << x << ' ' << d[x] << endl;
        if (c[x] == n) return true;
        for (int i = head[x]; i; i = edge[i].next)
            if (d[edge[i].to] < d[x] - t * edge[i].val + f[x])
            {
                d[edge[i].to] = d[x] - t * edge[i].val + f[x];
                c[edge[i].to] = c[x] + 1;
                if (!v[edge[i].to])
                    v[edge[i].to] = 1, q.push(edge[i].to);
            }
    }
    return false;
}

bool check(double t)
{
    for (int i = b.size() - 1; i >= 0; --i)
        if (spfa(b[i], t)) return true;
    return false;
}

void dfs(int x)
{
    v[x] = 1;
    for (int i = head[x]; i; i = edge[i].next)
        if (!v[edge[i].to])
            dfs(edge[i].to);
}

int main()
{
    cin >> n >> m;
    double l = 0, r = 0;
    for (int i = 1; i <= n; ++i)
        cin >> f[i], r += f[i];
    for (int x, y, i = 1; i <= m; ++i)
        x = read(), y = read(), add(x, y, read());
    for (int i = 1; i <= n; ++i)
        if (!v[i])
            b.push_back(i), dfs(i);
    while (r - l > 1e-5)
    {
        double mid = (l + r) / 2;
        if (check(mid)) l = mid;
        else r = mid;
    }
    cout << fixed << setprecision(2) << l << endl;
    return 0;
}

BZOJ3232 圈地游戏

大概这道题想说的是可以从一大堆点开始绕好几圈。最小割,选中最后与原点连通的格子,割掉这些格子边界上的边。

inf 开 1e10 就 WA,1e8 就 AC,这可真是谜了。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <bits/stdc++.h>
using namespace std;

#define N 30000
#define M 200000
#define inf 1e8
#define eps 1e-8

int n, m, sum, val[55][55], cost1[55][55], cost2[55][55];
int s, t, pos[55][55], head[N], cnt, d[N];

struct graph
{
    int next, to; double val;
    graph() {}
    graph(int _next, int _to, double _val)
    : next(_next), to(_to), val(_val) {}
} edge[M];

inline void add(int x, int y, double z)
{
    edge[++cnt] = graph(head[x], y, z);
    head[x] = cnt;
    edge[++cnt] = graph(head[y], x, 0);
    head[y] = cnt;
}

inline int read()
{
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

queue<int> q;

bool bfs()
{
    memset(d, 0, sizeof d);
    while (!q.empty()) q.pop();
    q.push(s); d[s] = 1;
    while (!q.empty())
    {
        int x = q.front(); q.pop();
        for (int i = head[x]; i; i = edge[i].next)
            if (edge[i].val > eps && !d[edge[i].to])
            {
                d[edge[i].to] = d[x] + 1;
                if (edge[i].to == t) return true;
                q.push(edge[i].to);
            }
    }
    return false;
}

double dfs(int x, double f)
{
    if (x == t) return f;
    double temp = f;
    for (int i = head[x]; i; i = edge[i].next)
        if (edge[i].val > eps && d[edge[i].to] == d[x] + 1)
        {
            double k = dfs(edge[i].to, min(temp, edge[i].val));
            if (k < eps) d[edge[i].to] = 0;
            edge[i].val -= k; edge[i ^ 1].val += k;
            if ((temp -= k) < eps) break;
        }
    return f - temp;
}

double dinic()
{
    double re = 0;
    while (bfs())
        re += dfs(s, inf);
    return re;
}

void init()
{
    memset(head, 0, sizeof head); cnt = 1;
}

double check(double mid)
{
    init();
    for (int i = 0; i <= n + 1; ++i)
        for (int j = 0; j <= m + 1; ++j)
            if (i == 0 || j == 0 || i == n + 1 || j == m + 1)
                add(pos[i][j], t, inf);
            else add(s, pos[i][j], val[i][j]);
    for (int i = 0; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            add(pos[i][j], pos[i + 1][j], cost1[i][j] * mid),
            add(pos[i + 1][j], pos[i][j], cost1[i][j] * mid);
    for (int i = 1; i <= n; ++i)
        for (int j = 0; j <= m; ++j)
            add(pos[i][j], pos[i][j + 1], cost2[i][j] * mid),
            add(pos[i][j + 1], pos[i][j], cost2[i][j] * mid);
    return sum - dinic();
}

int main()
{
    cin >> n >> m;
    s = 0, t = 1;
    for (int tot = 1, i = 0; i <= n + 1; ++i)
        for (int j = 0; j <= m + 1; ++j)
            pos[i][j] = ++tot;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            val[i][j] = read(), sum += val[i][j];
    for (int i = 0; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            cost1[i][j] = read();
    for (int i = 1; i <= n; ++i)
        for (int j = 0; j <= m; ++j)
            cost2[i][j] = read();
    double l = 0, r = sum;
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid) < eps) r = mid;
        else l = mid;
    }
    cout << fixed << setprecision(3) << l << endl;
    return 0;
}