【BZOJ 1449】 1449: [JSOI2009]球队收益 (最小费用流)

 

1449: [JSOI2009]球队收益

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 841  Solved: 483

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

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 }
View Code

 

2017-04-01 08:20:09

posted @ 2017-04-01 08:20  konjak魔芋  阅读(243)  评论(0编辑  收藏  举报