题目大意:在一个篮球联赛里,有n支球队,球队的支出是和他们的胜负场次有关系的,具体来说,第i支球队的赛季总支出是 Ci∗x2+Di∗y2,Di<=Ci 。其中x,y分别表示这只球队本赛季的胜负场次。现在赛季进行到了一半,每只球队分别取得了win[i]场胜利和lost[i]场失利。而接下来还有m场比赛要进行。问联盟球队的最小总支出是多少。
对于每支队伍,计算出还有打 dui 场比赛,然后初始的时候我们假设所有队伍的比赛状态都是输,即 win[i]=win[i],lost[i]=lost[i]+du[i]
然后考虑每赢一场的对总支出的影响, c[i]∗(win[i]+1)2−c[i]∗win[i]2+d[i]∗(lost[i]−1)2−d[i]∗lost[i]2
化简后得到 c[i]+d[i]+2∗win[i]∗c[i]−2∗lost[i]∗d[i]
对于每支队伍来说,剩多少场比赛,就从这支队伍代表的点向汇点连几条边,每条边的容量为1,费用为上式的答案,每连完一条边, win[i]++,lost[i]−− ,重新计算边权。
每场比赛必有一支队伍获胜,所有源点向每场比赛代表的点连边,容量为1,费用为0
每场比赛向进行的两支队伍连边,容量为1,费用为0.
然后跑费用流即可。
注意最后的答案要加入初值 ∑ni=1lost[i]∗lost[i]∗d[i]+win[i]∗win[i]∗c[i]
#include
#include
#include
#include
#include
#include
#define N 300010
#define inf 1000000000
using namespace std;
int n,tot,c[N],d[N],cost[N],remain[N],point[N],nxt[N],v[N],ctx[N];
int cty[N],du[N],dx[N],dy[N],dis[N],can[N],last[N],ans,m,lost[N],win[N],S,T,cnt[N];
void add(int x,int y,int z,int k)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; cost[tot]=k;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; cost[tot]=-k;
}
int addflow(int s,int t)
{
int now=t; int ans=inf;
while (now!=s) {
ans=min(ans,remain[last[now]]);
now=v[last[now]^1];
}
now=t;
while (now!=s){
remain[last[now]]-=ans;
remain[last[now]^1]+=ans;
now=v[last[now]^1];
}
return ans;
}
bool spfa(int s,int t)
{
for (int i=1;i<=t;i++) dis[i]=inf,can[i]=0;
queue<int> p; p.push(s); dis[s]=0; can[s]=1;
while (!p.empty()){
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=nxt[i])
if (remain[i]&&dis[v[i]]>dis[now]+cost[i]){
dis[v[i]]=dis[now]+cost[i];
last[v[i]]=i;
if(!can[v[i]]) {
can[v[i]]=1;
p.push(v[i]);
}
}
can[now]=0;
}
if (dis[t]==inf) return false;
int flow=addflow(s,t);
ans+=flow*dis[t];
return true;
}
void solve(int s,int t)
{
while(spfa(s,t));
}
int main()
{
freopen("a.in","r",stdin);
// freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
tot=-1;
memset(point,-1,sizeof(point));
for (int i=1;i<=n;i++) scanf("%d%d%d%d",&win[i],&lost[i],&c[i],&d[i]);
S=n+m+1; T=S+1;
for (int i=1;i<=m;i++) {
int x,y; scanf("%d%d",&x,&y);
add(S,i,1,0); dx[i]=x; dy[i]=y;
du[x]++; du[y]++;
add(i,x+m,1,0); ctx[i]=tot;
add(i,y+m,1,0); cty[i]=tot;
}
for (int i=1;i<=n;i++) lost[i]+=du[i];
for (int i=1;i<=n;i++) ans+=c[i]*win[i]*win[i]+d[i]*lost[i]*lost[i];
for (int i=1;i<=n;i++)
for (int j=1;j<=du[i];j++){
int t=win[i]*2*c[i]+c[i]+d[i]-lost[i]*2*d[i];
add(i+m,T,1,t);
win[i]++; lost[i]--;
}
solve(S,T);
printf("%d\n",ans);
}