[JSOI2009] 球队收益 (费用流)

终于来发题解啦!

pdf版题解

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<climits>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+c-‘0‘;c=getchar();}
    return f*ans;
}
queue<int> que;
const int MAXN=400001;
struct node{
    int u,v,w,cost,nex;
}x[MAXN];
int head[MAXN],dis[MAXN],vis[MAXN],S,T,cnt,cost,INF=INT_MAX;
void add(int u,int v,int cost,int w){
//    printf("u:%d v:%d cost:%d w:%d\n",u,v,cost,w);
    x[cnt].u=u,x[cnt].v=v,x[cnt].cost=cost,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;swap(u,v);w=0,cost=-cost;
    x[cnt].u=u,x[cnt].v=v,x[cnt].cost=cost,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
}
bool spfa(){
    memset(vis,0,sizeof(vis));memset(dis,127/3,sizeof(dis));int inf=dis[0];dis[S]=0;
    que.push(S);
    while(!que.empty()){
        int xx=que.front();que.pop();
        for(int i=head[xx];i!=-1;i=x[i].nex){
            if(dis[x[i].v]>dis[xx]+x[i].cost&&x[i].w){
                dis[x[i].v]=dis[xx]+x[i].cost;
                if(!vis[x[i].v]){
                    vis[x[i].v]=1;
                    que.push(x[i].v);
                }
            }
        }vis[xx]=0;
    }return dis[T]!=inf;
}
int dfs(int u,int flow){
    if(u==T) return flow;
    vis[u]=1;int used=0;
    for(int i=head[u];i!=-1;i=x[i].nex){
        if(!vis[x[i].v]&&x[i].w&&dis[x[i].v]==dis[u]+x[i].cost){
            int slow=dfs(x[i].v,min(flow-used,x[i].w));used+=slow;
            x[i].w-=slow,x[i^1].w+=slow;
            cost+=slow*x[i].cost;
            if(flow==used) break;
        }
    }if(!used) dis[u]=-1;
    vis[u]=0;
    return used;
}
int dinic(){
    int ans=0;
    while(spfa()){memset(vis,0,sizeof(vis));ans+=dfs(S,INF);}
    return ans;
}
int n,m,c[MAXN],Sum,d[MAXN],a[MAXN],b[MAXN],sum[MAXN];
int main(){
    memset(head,-1,sizeof(head));
    n=read(),m=read();S=0,T=n+m+1;
    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++){
        add(S,i,0,1);
        int u=read(),v=read();
        b[u]++,b[v]++;
        sum[u]++,sum[v]++;
        add(i,u+m,0,1),add(i,v+m,0,1);
    }
    for(int i=1;i<=n;i++) Sum+=c[i]*a[i]*a[i]+d[i]*b[i]*b[i];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=sum[i];j++){
            add(i+m,T,c[i]*(2*a[i]+1)-d[i]*(2*b[i]-1),1);
            a[i]++,b[i]--;
        }
    }dinic();
    printf("%d\n",Sum+cost);
}

原文地址:https://www.cnblogs.com/si-rui-yang/p/10498127.html

时间: 2024-10-01 09:31:37

[JSOI2009] 球队收益 (费用流)的相关文章

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

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

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

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 [思路] 费用拆分,

[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/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. 因为费用的改变是包含平方的,所以我们需要拆边来做. 第

【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 [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]*

【BZOJ1449&amp;&amp;2895】球队预算 [费用流]

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

bozj 1449/2895: 球队预算 -- 费用流

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