题目链接: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 }