【BZOJ 1449】 1449: [JSOI2009]球队收益 (最小费用流)
1449: [JSOI2009]球队收益
Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 841 Solved: 483Description
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
【题意】
给定n支球队,第i支球队已经赢了win[i]场,输了lose[i]场,接下来还有m场比赛,每个球队最终的收益为Ci∗x[i]^2+Di∗y[i]^2,其中x[i]为最终的胜场,y[i]为最终的负场,求最小化收益。
【分析】
先差分,再拆边。
注意,输赢都有贡献,普通做法不行。直接当成那些比赛所有人都输,那只要计算赢的那个人的贡献。
然后差分:
赢k-1场:c[i]*(win[i]+(k-1))^2+d[i]*(sm[i]+lose[i]-(k-1))^2
赢k场:c[i]=(win[i]+k)^2+d[i]*(sm[i]+lose[i]-k)^2
相减得到赢第k场:c[i]*(2*win[i]-(2*k-1))-d[i]*(2*(lose[i]+sm[i])-(2*k-1))
这是单调的,所以把原本的贡献+最大费用流就好了。
可以膜Po姐:http://blog.csdn.net/PoPoQQQ/article/details/46619517
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define Maxn 5010 9 #define Maxm 1010 10 #define INF 0xfffffff 11 12 int mymin(int x,int y) {return x<y?x:y;} 13 14 int win[Maxn],lose[Maxn],c[Maxn],d[Maxn],sm[Maxn]; 15 16 struct node 17 { 18 int x,y,f,c,o,next; 19 }t[Maxm*100]; 20 int len,first[Maxn*2]; 21 22 void ins(int x,int y,int f,int c) 23 { 24 t[++len].x=x;t[len].y=y;t[len].f=f;t[len].c=c; 25 t[len].next=first[x];first[x]=len;t[len].o=len+1; 26 t[++len].x=y;t[len].y=x;t[len].f=0;t[len].c=-c; 27 t[len].next=first[y];first[y]=len;t[len].o=len-1; 28 } 29 30 queue<int > q; 31 int st,ed; 32 int flow[Maxn*2],pre[Maxn*2],dis[Maxn*2]; 33 bool inq[Maxn*2]; 34 bool bfs() 35 { 36 while(!q.empty()) q.pop(); 37 // memset(dis,-1,sizeof(dis)); 38 for(int i=1;i<=ed;i++) dis[i]=INF; 39 memset(inq,0,sizeof(inq)); 40 flow[st]=INF;q.push(st);dis[st]=0; 41 inq[st]=1; 42 while(!q.empty()) 43 { 44 int x=q.front(); 45 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 46 { 47 int y=t[i].y; 48 if(dis[y]>dis[x]+t[i].c) 49 { 50 dis[y]=dis[x]+t[i].c; 51 pre[y]=i; 52 flow[y]=mymin(flow[x],t[i].f); 53 if(!inq[y]) 54 { 55 q.push(y); 56 inq[y]=1; 57 } 58 } 59 } 60 q.pop();inq[x]=0; 61 } 62 if(dis[ed]==INF) return 0; 63 return 1; 64 } 65 66 int sum=0; 67 int max_flow() 68 { 69 while(bfs()) 70 { 71 int x=ed; 72 sum+=flow[ed]*dis[ed]; 73 int a=flow[ed]; 74 while(x!=st) 75 { 76 t[pre[x]].f-=a; 77 t[t[pre[x]].o].f+=a; 78 x=t[pre[x]].x; 79 } 80 } 81 printf("%d\n",sum); 82 } 83 84 void output() 85 { 86 for(int i=1;i<=len;i+=2) 87 printf("%d -> %d %d %d\n",t[i].x,t[i].y,t[i].f,t[i].c); 88 } 89 90 int main() 91 { 92 int n,m; 93 scanf("%d%d",&n,&m); 94 for(int i=1;i<=n;i++) scanf("%d%d%d%d",&win[i],&lose[i],&c[i],&d[i]); 95 st=n+m+1;ed=st+1; 96 memset(sm,0,sizeof(sm)); 97 for(int i=1;i<=m;i++) 98 { 99 int x,y; 100 scanf("%d%d",&x,&y); 101 ins(x,n+i,1,0); 102 ins(y,n+i,1,0); 103 ins(n+i,ed,1,0); 104 sm[x]++;sm[y]++; 105 } 106 for(int i=1;i<=n;i++) 107 { 108 for(int j=1;j<=sm[i];j++) ins(st,i,1,c[i]*(2*win[i]+2*j-1)-d[i]*(2*(sm[i]+lose[i])-(2*j-1))); 109 sum+=c[i]*win[i]*win[i]+d[i]*(lose[i]+sm[i])*(lose[i]+sm[i]); 110 } 111 max_flow(); 112 return 0; 113 }
2017-04-01 08:20:09