【题解】JSOI2009球队收益 / 球队预算

  为什么大家都不写把输的场次增加的呢?我一定要让大家知道,这并没有什么关系~所以 \(C[i] <= D[i]\) 的条件就是来卖萌哒??

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
#define INF 99999999
int n, m, S, T, rec[maxn], flow[maxn], a[maxn], b[maxn];
int ans, tot, c[maxn], d[maxn], dis[maxn], num[maxn];
bool vis[maxn];

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < ‘0‘ || c > ‘9‘) { if(c == ‘-‘) k = -1; c = getchar(); }
    while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = getchar();
    return x * k;
}

struct edge {
    int cnp, to[maxn], last[maxn], head[maxn], f[maxn], co[maxn];
    edge() { cnp = 2; }
    void add(int u, int v, int fl, int w) {
        to[cnp] = v, f[cnp] = fl, co[cnp] = w, last[cnp] = head[u], head[u] = cnp ++;
        to[cnp] = u, f[cnp] = 0, co[cnp] = -w, last[cnp] = head[v], head[v] = cnp ++;
    }
}E1;

struct node {
    int x, y;
}P[maxn];

int multi(int x) { return x * x; }
void Build() {
    S = 0, T = 3 * m + 3;
    for(int i = 1; i <= n; i ++) {
        int A = a[i] + num[i], B = b[i];
        if(num[i]) rec[i] = tot + 1;
        for(int j = 1; j <= num[i]; j ++) {
            ++ tot;
            E1.add(tot, T, 1, 2 * B * d[i] - 2 * A * c[i] + c[i] + d[i]);
            if(j != num[i]) E1.add(tot, tot + 1, INF, 0);
            A --, B ++;
        }
    }
    for(int i = 1; i <= m; i ++) {
        E1.add(S, ++ tot, 1, 0);
        E1.add(tot, rec[P[i].x], 1, 0);
        E1.add(tot, rec[P[i].y], 1, 0);
    }
}

bool SPFA() {
    queue <int> q;
    for(int i = 0; i <= T; i ++) dis[i] = INF, vis[i] = 0;
    q.push(S); dis[S] = 0; flow[S] = INF;
    while(!q.empty()) {
        int u = q.front(); q.pop(); vis[u] = 0;
        for(int i = E1.head[u]; i; i = E1.last[i]) {
            int v = E1.to[i];
            if(!E1.f[i]) continue;
            if(dis[v] > dis[u] + E1.co[i]) {
                dis[v] = dis[u] + E1.co[i];
                rec[v] = i, flow[v] = min(flow[u], E1.f[i]);
                if(!vis[v]) q.push(v), vis[v] = 1;
            }
        }
    }
    if(dis[T] != INF) return 1;
    return 0;
}

int Max_Flow() {
    int ans = 0, cost = 0;
    while(SPFA()) {
        int u = T;
        while(u != S) {
            int t = rec[u];
            E1.f[t] -= flow[T], E1.f[t ^ 1] += flow[T];
            u = E1.to[t ^ 1];
        }
        ans += flow[T], cost += dis[T] * flow[T];
    }
    return cost;
}

int main() {
    n = read(), m = read();
    for(int i = 1; i <= n; i ++) {
        a[i] = read(), b[i] = read(), c[i] = read(), d[i] = read();
    }
    for(int i = 1; i <= m; i ++) {
        int x = read(), y = read();
        num[x] ++, num[y] ++; P[i].x = x, P[i].y = y;
    }
    for(int i = 1; i <= n; i ++)
        ans += c[i] * multi(a[i] + num[i]) + d[i] * multi(b[i]);
    Build();
    printf("%d\n", ans + Max_Flow());
    return 0;
}

原文地址:https://www.cnblogs.com/twilight-sx/p/10380993.html

时间: 2024-10-05 03:10:07

【题解】JSOI2009球队收益 / 球队预算的相关文章

【BZOJ1449/2895】[JSOI2009]球队收益/球队预算 最小费用最大流

[BZOJ2895]球队预算 Description 在一个篮球联赛里,有n支球队,球队的支出是和他们的胜负场次有关系的,具体来说,第i支球队的赛季总支出是Ci*x^2+Di*y^2,Di<=Ci.(赢得多,给球员的奖金就多嘛) 其中x,y分别表示这只球队本赛季的胜负场次.现在赛季进行到了一半,每只球队分别取得了a[i]场胜利和b[i]场失利.而接下来还有m场比赛要进行.问联盟球队的最小总支出是多少. Input 第一行n,m 接下来n行每行4个整数a[i],b[i],Ci,Di 再接下来m行每

【bzoj1449/bzoj2895】[JSOI2009]球队收益/球队预算 费用流

题目描述 输入 输出 一个整数表示联盟里所有球队收益之和的最小值. 样例输入 3 3 1 0 2 1 1 1 10 1 0 1 3 3 1 2 2 3 3 1 样例输出 43 题解 费用流 由于存在一个赢一个输,比较难算.我们可以先假设它们都输掉,然后再安排赢的情况. 设fi为i还要打的比赛数目,那么初始的收益为∑ci*wi^2+di*(li+fi)^2. S->每场比赛,容量为1,费用为0. 每场比赛->比赛的两队,容量为1,费用为0. 因为费用的改变是包含平方的,所以我们需要拆边来做. 第

【BZOJ-1449&amp;2895】球队收益&amp;球队预算 最小费用最大流

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 648  Solved: 364[Submit][Status][Discuss] Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 10 1 0 1 3 3 1 2 2 3 3 1 Sample Output 43 HINT Source 2895: 球队预算

bzoj 1449 [JSOI2009]球队收益(费用拆分,最小费用流)

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 547  Solved: 302[Submit][Status][Discuss] Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 10 1 0 1 3 3 1 2 2 3 3 1 Sample Output 43 HINT Source [思路] 费用拆分,

BZOJ 1449: [JSOI2009]球队收益( 最小费用最大流)

先考虑假如全部输了的收益. 再考虑每场比赛球队赢了所得收益的增加量,用这个来建图.. -------------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<iostre

[JSOI2009]球队收益

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1124  Solved: 635[Submit][Status][Discuss] Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 10 1 0 1 3 3 1 2 2 3 3 1 Sample Output 43 HINT Source 二次费用流模板题.

bzoj1449 [JSOI2009]球队收益

Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 10 1 0 1 3 3 1 2 2 3 3 1 Sample Output 43 orz huzecong 神犇的想法果然与众不同 首先看上去像网络流.这样就够了 先假设每场比赛两队都是输的,那么接下来转换的时候只要把其中一对变成赢的就好了. 考虑一支球队已经赢了x场输了y场现在要把输的y场之一变成赢的,考虑这样对答案的影响 原来是C[i]*

BZOJ 1449 球队收益(最小费用最大流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1449 题意: 思路:首先,我们假设后面的M场比赛两方都是输的,即初始时的lose[i]再加上i参加的场次.这样,后面对于i,每赢一场的收益增加值为: 之后win[i]++,lose[i]--.至此,我们得到建图的方法: (1)源点到每场比赛连流量1,费用0: (2)每场比赛向双方连流量1,费用0: (3)每个人到汇点连x条边(x为该人在M场比赛中出现的次数),流量1,费用为上面计算出的

BZOJ 1449 JSOI2009 球队收益 费用流

题目大意:给定n支球队,第i支球队已经赢了wini场,输了losei场,接下来还有m场比赛,每个球队最终的收益为Ci?x2i+Di?y2i,其中xi为最终的胜场,yi为最终的负场 求最小化收益 考虑一只球队,其收益与在接下来的比赛中的胜场数关系为: 赢0场 Ci?win2i+Di?(di+losei)2 赢1场 Ci?(wini+1)2+Di?(di+losei?1)2 赢2场 Ci?(wini+2)2+Di?(di+losei?2)2 - 赢di场 Ci?(wini+di)2+Di?lose2