hdu4406 GPA (最大费用最大流)

 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4406

【题意】M个课程,N天复习,每天有K节课,每复习一节课课程分数增加1。aij,限制第i天能不能进行j课程的复习。给定每个课程基准分,学分,GPA计算公式。问,保证所有课程及格的情况下,求最高GPA。

【分析】费用流问题,最大费用最大流。

 

如何灵活的修改模板进行最小、最大费用?得研读研读算法的具体过程

 

MCMF 模板:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define maxn 1010
  9 #define maxm 20010
 10 const int INF=1000000000;
 11 
 12 struct Node
 13 {
 14     int u,v,flow,next;
 15     double cost;
 16 };
 17 
 18 struct MCMF_flow
 19 {
 20     Node edges[maxm];
 21     int e,S,T;
 22     int head[maxn],in[maxn],pre[maxn],flow[maxn];
 23     double cost[maxn];
 24 
 25     void init()
 26     {
 27         e = 0;
 28         memset(head, -1, sizeof(head));
 29     }
 30     void add(int u,int v,int flow,double cost)
 31     {
 32         edges[e].u=u;
 33         edges[e].v=v;
 34         edges[e].flow=flow;
 35         edges[e].cost=cost;
 36         edges[e].next=head[u];
 37         head[u]=e++;
 38     }
 39 
 40 
 41     void AddEdge(int u,int v,int flow,double cost)
 42     {
 43         add(u,v,flow,cost);
 44         add(v,u,0,-cost);
 45     }
 46 
 47 
 48     int OK(int s,int t)
 49     {
 50         int i,u,v,f;
 51         double c;
 52         queue<int> Q;
 53 
 54         memset(pre,-1,sizeof(pre));
 55         memset(in,0,sizeof(in));
 56         memset(flow,0,sizeof(flow));
 57         for(i=0; i<=t; i++) cost[i]=-1.0*INF;
 58         cost[s]=0;
 59         flow[s]=INF;
 60         Q.push(s);
 61         in[s]=1;
 62         while(!Q.empty())
 63         {
 64             u=Q.front();
 65             Q.pop();
 66 
 67             in[u]=0;
 68             for(i=head[u]; i!=-1; i=edges[i].next)
 69             {
 70                 v=edges[i].v;
 71                 f=edges[i].flow;
 72                 c=edges[i].cost;
 73                 if(f>0&&cost[v]<cost[u]+c)
 74                 {
 75                     cost[v]=cost[u]+c;
 76                     flow[v]=min(flow[u],f);
 77                     pre[v]=i;
 78                     if(!in[v]) Q.push(v),in[v]=1;
 79                 }
 80             }
 81         }
 82         return flow[t];
 83     }
 84 
 85 
 86     int MinCost(int s,int t)
 87     {
 88         int minflow,mincost=0,i;
 89 
 90         while(minflow=OK(s,t))
 91         {
 92             for(i=pre[t]; i!=-1; i=pre[edges[i].u])
 93             {
 94                 mincost+=minflow*edges[i].cost;
 95                 edges[i].flow-=minflow;
 96                 edges[i^1].flow+=minflow;
 97             }
 98         }
 99         return mincost;
100 
101 
102     }
103     void solve(int *pp, int s)
104         {
105             for (int i=head[s];i!=-1;i=edges[i].next)
106             {
107                 pp[edges[i].v] += edges[i^1].flow;
108             }
109         }
110 }MC;
111 
112 
113 
114 
115 
116 
117 int N,M,K;
118 
119 int w[maxn];
120 int p[maxn];
121 int a[maxn][maxn];
122 
123 double calc(int p, int w)
124 {
125     return (4.0 - 3.0 * (100 - p) * (100 - p)/1600.0) * w;
126 }
127 int main()
128 {
129     while (scanf("%d%d%d",&N,&K,&M)==3)
130     {
131         if (N == 0)
132             break;
133 
134         int s = 0, t = N + M + 1;
135         double sum = 0;
136 
137         for (int i=1; i<=M; i++)
138         {
139             scanf("%d",&w[i]);
140             sum = sum + w[i];
141         }
142         for (int i=1; i<=M; i++)
143         {
144             scanf("%d",&p[i]);
145         }
146         for (int i=1; i<=N; i++)
147         {
148             for (int j=1; j<=M; j++)
149             {
150                 scanf("%d",&a[i][j]);
151             }
152         }
153         MC.init();
154         for (int i=1; i<=N; i++)
155         {
156             MC.AddEdge(i+M, t, K, 0);
157             for (int j=1; j<=M; j++)
158                 if (a[i][j])
159                 {
160                     MC.AddEdge(j,M+i,K,0);
161                 }
162         }
163         for (int i=1; i<=M; i++)
164         {
165             if (p[i] < 60)
166             {
167                 MC.AddEdge(s, i, 60 -  p[i], 1.0 * INF);
168                 double last = calc(60, w[i]);
169                 for (int j=61; j<=100; j++)
170                 {
171                     double cur = calc(j, w[i]);
172                     MC.AddEdge(s,i,1, cur - last);
173                     last = cur;
174                 }
175             }
176             else
177             {
178                 double last = calc(p[i], w[i]);
179                 for (int j=p[i] + 1; j<=100; j++)
180                 {
181                     double cur = calc(j, w[i]);
182                     MC.AddEdge(s, i, 1, cur- last);
183                     last =cur;
184                 }
185             }
186         }
187         MC.MinCost(s, t);
188 
189         MC.solve(p,s);
190 
191         bool flag = 0;
192         double ans = 0.0;
193         for (int i=1; i<=M; i++)
194         {
195             if (p[i] >= 60)
196             {
197                 ans += calc(p[i], w[i]) / sum;
198             }
199             else
200             {
201                 flag = 1;
202                 break;
203             }
204         }
205         if (flag)
206         {
207             ans = 0;
208         }
209         printf("%.6lf\n",ans);
210     }
211     return 0;
212 }
hdu4406

 

转载于:https://www.cnblogs.com/wangsouc/articles/3712673.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值