1449: [JSOI2009]球队收益
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 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
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()
{;}