[JSOI2009]球队收益

本文针对JSOI2009题目《球队收益》进行了解析,介绍了通过建立最小费用最大流模型来解决该问题的方法。文章详细解释了如何根据球队胜负情况调整收益计算,以及如何构造图模型来求解所有球队收益之和的最小值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1449: [JSOI2009]球队收益

Time Limit: 5 Sec   Memory Limit: 64 MB
Submit: 992   Solved: 563
[ 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


  对于单独一支球队来说,假设其已经赢了n场,输了m场。当其再赢

    一场时,增加的收益为Ci*((n+1)^2-n^2),即Ci*(2n+1),输了同理。且每

    赢一场或输一场增加的收益都是递增的。所以我们可以直接统计每支球队接

    下来要比赛的局数,并分别为赢了或输了第几场比赛建边,因为收益递增,

    且求最小费用,所以,一定是按照赢或输的累积次数流的。

    对于一场比赛来说,只有两种结果,所以要对其建一条容量为一的入边,并

    建两条容量为1的出边,分别指向两种结果。

    但这样,对于其中一种结果,容量为一,不能分别流向两支球队去修改各自

    的收益。又不可增大原来决定结果的三条边的流量,因为这样会出现,流同

    时流向两种结果的情况,不合法。

    所以,我们只修改获胜球队(或失败球队)的收益。最初,我们先将一个球队

    的总收益算成接下来都会输的结果,这样每赢一场增加的收益就是

    Ci*((n+1)^2-n^2)-Di*((m+1)^2-m^2),问题就解决了。


先全建都输的收益-》之后再加上与赢的差

#include<iostream>

#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#include<cstdlib>
#include<algorithm>
#define V 10005
#define mod 1000000007
#define LL long long
using namespace std;
int n,m,T,S,rt;
int fw,ans;
int w[V],l[V],c[V],d[V];
int a[V],b[V],pre[V],dep[V],q[V],dis[V],pr[V],p;
int ins[V],s[V];
struct da
{
 int f,to,next,dis,cast;       
}Edge[V*100];
int head[V],tot;
inline void add(int x,int y,int zz,int dd)
{
   Edge[tot].f=x;
  Edge[tot].to=y;
  Edge[tot].dis=zz;
  Edge[tot].cast=dd;
  Edge[tot].next=head[x];
  head[x]=tot++;  
  Edge[tot].f=y;
  Edge[tot].to=x;
  Edge[tot].dis=0;
  Edge[tot].cast=-dd;
  Edge[tot].next=head[y];
  head[y]=tot++;    
}
inline bool FIND(int st,int ed) {
     //cout<<st<<endl;
memset(dis,0x3f,sizeof(dis));
memset(ins,false,sizeof(ins));
memset(pr,0,sizeof(pr));
memset(s,0x3f,sizeof(s));
int inf;
inf = dis[0];
queue <int> q;
q.push(st), dis[st] = 0, s[st] = inf;
while(!q.empty()) {
int op = q.front(); q.pop();

for(int i = head[op] ; i != -1 ; i = Edge[i].next) {
if(Edge[i].dis>0&&dis[Edge[i].to]>dis[op]+Edge[i].cast) {
dis[Edge[i].to] = dis[op]+Edge[i].cast;
pr[Edge[i].to] = i;
s[Edge[i].to] = min(s[op],Edge[i].dis);
   //printf("i &&& %d  to  %d  %d\n",i,Edge[i].to,dis[Edge[i].to]);//cout<<dis[Edge[i].to]<<"  "<<Edge[i].to<<"  "<<ed<<endl;
if(!ins[Edge[i].to]) {
ins[Edge[i].to] = true;
q.push(Edge[i].to);
}
}
}
ins[op] = false;
} //cout<<Cost<<endl;
if(dis[ed]==inf) return false;
fw+= s[ed];
ans+= dis[ed]*s[ed];
int w = ed;
while(w!=st) {
Edge[pr[w]].dis -= s[ed];
Edge[pr[w]^1].dis += s[ed];
w = Edge[pr[w]].f;
}
//cout<<Cost<<"  $%"<<endl;
return true;

}
inline int haha()
{
      // freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
  //freopen("napkin.in","r",stdin); freopen("napkin.out","w",stdout);
       memset(head,-1,sizeof(head));
     cin>>n>>m;
     T=n+m+2;
     int fd=0,csd=0;
     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",&a[i],&b[i]);
      l[a[i]]++;l[b[i]]++;
     }
     for(int i=1;i<=n;i++)
     ans+=c[i]*w[i]*w[i]+d[i]*l[i]*l[i];
     for(int i=1;i<=m;i++)
     {
       add(0,i,1,0);
       add(i,m+a[i],1,0);        
       add(i,m+b[i],1,0);
       int cs;
       cs=c[a[i]]*(2*w[a[i]]+1)-d[a[i]]*(2*l[a[i]]-1);
       add(m+a[i],T,1,cs);
        w[a[i]]++;l[a[i]]--;
        cs=c[b[i]]*(2*w[b[i]]+1)-d[b[i]]*(2*l[b[i]]-1);
        w[b[i]]++;l[b[i]]--;
        add(m+b[i],T,1,cs); 
      }
  while(FIND(S,T));
   cout<<csd+ans;
   return 0;
}
int gg=haha();
int main()
{;}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值