bzoj球队收益

题面  点击打开链接

球队的收益随场数递增 (tot球队参加的总比赛数)

先假设以后的比赛全输

赢一场收益S1=Ci*(win1+1)^2+Di(losei+tot-1)^2;

赢二场S2=Ci*(win1+2)^2+Di(losei+tot-2)^2;

****

x场Ci*(win1+x)^2+Di(losei+tot-x)^2;

根据上面的式子

赢第一场增加的收益=S1-ci*win1^2+di*(losei+tot)^2;

赢第二场增加的收益=S2-S1

****

赢第x场=ci*(2*win+2*x-1)-di(2*tot+2*lose-2*x+1)

从源点向n个队建边,向第i个点见tot[i]条边,第i条边权值为Si-Si-1

每个队向参加的比赛连边,f=1,c=0;

每场比赛向汇点连边,f=1,c=0;

跑一遍最大流最小花费

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 5005
using namespace std;
int n,m,cnt=0,cost=0,sum=0;
int w[N],l[N],c[N],d[N];
int a[N];
struct edge
{
     int fr,to,ne,w,co; 
}b[N*200];
int head[N+1005],k=0;
void add(int u,int v,int w,int c)
{
     edge E1={u,v,head[u],w,c};
     b[k]=E1; head[u]=k++;
     edge E2={v,u,head[v],0,-c};
     b[k]=E2; head[v]=k++;
}
inline void read()
{
     int x,y;
     scanf("%d%d",&n,&m);
     for(int i=1;i<=n;i++){
       scanf("%d%d%d%d",&w[i],&l[i],&c[i],&d[i]);
     }
     for(int i=1;i<=m;i++){
       scanf("%d%d",&x,&y);
       add(x,n+i,1,0);
       add(y,n+i,1,0);
       a[x]++; a[y]++;
     }
     for(int i=1;i<=n;i++){
       sum+=c[i]*w[i]*w[i]+d[i]*(a[i]+l[i])*(a[i]+l[i]);
     }
}
void build()
{
     cnt=n+m+1;
     int t=0;
     for(int i=1;i<=n;i++){
        add(0,i,0,0);
        for(int j=1;j<=a[i];j++){
           t=c[i]*(2*w[i]+2*j-1)-d[i]*(2*a[i]+2*l[i]-2*j+1);
           add(0,i,1,t);
        }
     }
     for(int i=1;i<=m;i++)
       add(n+i,cnt,1,0);
}
int dis[N+1005],vis[N+1005],pr[N+1005],cc[N+1005];
bool spfa()
{
     memset(dis,0xf,sizeof(dis));
     memset(vis,0,sizeof(vis));
     memset(pr,-1,sizeof(pr));
     memset(cc,0,sizeof(cc));
     queue<int> q;
     q.push(0);vis[0]=1;dis[0]=0;cc[0]=0x7fffffff;
     while(!q.empty())
     {
           int z=q.front();q.pop();vis[z]=0;
           for(int i=head[z];i!=-1;i=b[i].ne)
           if(b[i].w&&dis[b[i].to]>dis[z]+b[i].co)
           {
                dis[b[i].to]=dis[z]+b[i].co;
                pr[b[i].to]=i;
                cc[b[i].to]=min(b[i].w,cc[z]);
                if(vis[b[i].to]==0){
                  vis[b[i].to]=1;
                  q.push(b[i].to);
                }
           }           
     }
     return pr[cnt]!=-1;
}
void mcmf()
{
     cost+=dis[cnt]*cc[cnt];
     int w=cnt;
     while(w!=0){
         b[pr[w]].w-=cc[cnt];
         b[pr[w]^1].w+=cc[cnt];
         w=b[pr[w]].fr;
     }
}
int main()
{
    //freopen("in.txt","r",stdin);
    memset(head,-1,sizeof(head));
    read();
    build();
    while(spfa()==1) mcmf();
      cost=sum+cost;
    printf("%d",cost);
   // while(1);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值