题意:现在你有m科课程需要学习,每个课程有一个基础分数,每学习该课程一个时间单位,该课程的分数就增加1分。现在有n天的学习时间,每天有K个单位时间,给出每天可以学习的课程,给出学分绩点的计算方式,求可以达到的最高的学分绩点,并且要求所有课程都要及格。
题解:这是一道费用流,大概就是每一分连一条边,费用就是收益,优先每门课及格,所以小于60分连的边的流量是离60分的数值费用都是无穷大,大于60分每一分连一条边流量是一费用是收益。求最大费用最大流即可(费用设为负数则可求最小费用最大流),若无穷大的数目足够,则全部可以及格,则费用就是答案
#include
#include
#define typef int
#define typec double
using namespace std;
const int E = 888888;
const int N = 10008;
const typef inff = 0x3f3f3f3f;
const typec infc = 1e8;
const typec inf = 1e4;
const int maxn = 88;
double w[maxn];
double ww, res;
int mp[maxn][maxn];
int base[maxn];
int n, m, kk;
int cc;
double getp(int id, int x){
if(x < 60) return 0;
return (4 - 3.0 * (100 - x) * (100 - x) / 1600) * w[id] / ww;
}
double cal(int id, int x){
//printf("getp %f\n", getp(id, x));
return getp(id, x + 1) - getp(id, x);
}
struct network{
int nv, ne, pnt[E], nxt[E];
int vis[N], que[N], head[N], pv[N], pe[N];
typef flow, cap[E]; typec cost, dis[E], d[N];
void addedge(int u, int v, typef c, typec w){
//printf("%d %d %d %f\n", u, v, c, w);
pnt[ne] = v; cap[ne] = c;
dis[ne] = +w; nxt[ne] = head[u]; head[u] = ne++;
pnt[ne] = u; cap[ne] = 0;
dis[ne] = -w; nxt[ne] = head[v]; head[v] = ne++;
}
double mincost(int src, int sink){
int i, k, f, r; typef mxf;
for(flow = 0, cost = 0; ; ){
memset(pv, -1, sizeof(pv));
memset(vis, 0, sizeof(vis));
for(i = 0; i < nv; i++) d[i] = infc;
d[src] = 0; pv[src] = src; vis[src] = 1;
for(f = 0, r = 1, que[0] = src; r != f; ){
i = que[f++]; vis[i] = 0;
//if(N == f) f = 0;
for(k = head[i]; k != -1; k = nxt[k]){
if(cap[k] && dis[k] + d[i] < d[pnt[k]]){
d[pnt[k]] = dis[k] + d[i];
if(0 == vis[pnt[k]]){
vis[pnt[k]] = 1;
que[r++] = pnt[k];
//if(N == r) r = 0;
}
pv[pnt[k]] = i; pe[pnt[k]] = k;
}
}
}
if(-1 == pv[sink]) break;
for(k = sink, mxf = inff; k != src; k = pv[k]){
if(cap[pe[k]] < mxf) mxf = cap[pe[k]];
}
flow += mxf; cost += d[sink] * mxf;
for(k = sink; k != src; k = pv[k]){
cap[pe[k]] -= mxf; cap[pe[k] ^ 1] += mxf;
}
}
//printf("cost %f\n", cost);
return cost;
}
void build(int v){
nv = v; ne = 0;
memset(head, -1, sizeof(head));
// 0 = src, 1 = sink
// 2 ~ m + 1 = p, m + 2 ~ m + n + 1 = day
for(int i = 1; i <= m; i++){
if(base[i] < 60){
addedge(0, 1 + i, 60 - base[i], -inf);
cc += 60 - base[i];
res += getp(i, 60);
}
else{
res += getp(i, base[i]);
}
for(int j = base[i] < 60 ? 60 : base[i]; j < 100; j++){
//printf("%d\n", j);
addedge(0, 1 + i, 1, -cal(i, j));
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(!mp[i][j]) continue;
addedge(j + 1, m + 1 + i, kk, 0);
}
addedge(m + 1 + i, 1, kk, 0);
}
}
}g;
int main(){
//n days, m course, kk class every day
while(scanf("%d%d%d", &n, &kk, &m), n + kk + m){
cc = ww = res = 0;
for(int i = 1; i <= m; i++){
scanf("%lf", w + i);
ww += w[i];
}
for(int i = 1; i <= m; i++) scanf("%d", base + i);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%d", &mp[i][j]);
}
}
g.build(n + m + 8);
//printf("res %f\n", res);
res += -g.mincost(0, 1);
//printf("%f %d %f\n", res, cc, -inf * cc);
res = res - inf * cc;
printf("%f\n", res < 0 ? 0 : res);
}
return 0;
}