hdu4406 GPA 费用流

http://acm.hdu.edu.cn/showproblem.php?pid=4406

GPA

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 828    Accepted Submission(s): 288

Problem Description

GPA(Grade-Point Average) is one way to measure students’ academic performance in PKU. Each course has an integer credit, ranges from 1 to 99. For each course, you will get a score at the end of the semester, which is an integer ranges from 0 to 100. Then you
can calculate the Grade-Point of this course with the following formula. (Your score is x and your Grade-Point is p, using real arithmetic)

Then you can get the GPA with the following formula (the Grade-Point of course i is pi, and the credit of course i is wi).

Now it is not far from the final exam, if you do not review, you can only get a basic score in each course.

You have n days to review. There are K classes in each day. For each class, only one course can be reviewed. After the review, your score in this course will exactly increase by 1. You can get more increment by spending more classes in this course. But the
score may not exceed 100.

For some reasons, not any course can be reviewed in any class. Each day you can only review some of the courses.

Now you want your GPA to be as high as possible, and at the same time, you do not want to fail in any course. Please calculate the highest GPA you can get.

Input

The input consists of several test cases. Each test case begins with 3 integers N (0<=N<=40), K(0<K<=20), M (0<M<=20), representing the number of days, the number of classes in each day and the number of courses. Next line contains M integers representing credits
of each course and M integers representing basic scores of each course (0<=score<=100). Next N lines contain an N*M matrix, the jth element in ith row means whether you can review course j in ith day, 1 means you can review
course j in ith day, 0 means you cannot. The Input ends with 0 0 0.

Output

For each test case, output the highest possible GPA, round to 6 digits after decimal point. If you have to fail a course, output 0.000000 instead.

Sample Input

2 10 3
1 1 2
50 60 90
1 1 0
1 0 1
2 20 4
1 1 1 1
50 50 50 40
1 1 1 0
0 0 0 1
0 0 0

Sample Output

2.757813
0.000000

Source

2012 ACM/ICPC Asia Regional Jinhua Online

题意:有m科课程需要学习,每个课程有一个基础分数,每学习该课程一个时间单位,该课程的分数就增加1分。现在有n天的学习时间,每天有K个单位时间,并且每天可以学习的课程是固定的,给出学分绩点的计算方式,求可以达到的最高的学分绩点,要求所有课程都要及格。

分析:费用和流量平方成正比的最大费用最大流,大白p366有模型。

每天向汇点连边,流量为K,费用0;每门课向符合要求的天连边,流量K费用0。

源点向每门课连边,为了保证每门课及格,连向s<60分的课流量60-s,费用-INF,然后每门课连min(100-s,40)条流量为1费用为f(x,p)-f(x+1,p)的边,可以发现每条边的费用随着x增大是递增的(负的),这样就保证增广的时候是按分数依次的。这里的f值可以化为整数,就避免了处理精度。

跑最小费用最大流,然后计算每门课的基础上加上各自的流量,如果还有小于60输出0.

/**
 * @author neko01
 */
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <set>
#include <map>
using namespace std;
typedef long long LL;
#define min3(a,b,c) min(a,min(b,c))
#define max3(a,b,c) max(a,max(b,c))
#define pb push_back
#define mp(a,b) make_pair(a,b)
#define clr(a) memset(a,0,sizeof a)
#define clr1(a) memset(a,-1,sizeof a)
#define dbg(a) printf("%d\n",a)
typedef pair<int,int> pp;
const double eps=1e-9;
const double pi=acos(-1.0);
const int INF=0x3f3f3f3f;
const LL inf=(((LL)1)<<61)+5;
const int maxn=505;
const int M=400010;
struct Edge{
    int to,next,cap,cost;
    Edge(int _to=0,int _next=0,int _cap=0,int _cost=0){
        to=_to;next=_next;cap=_cap;cost=_cost;
    }
}e[M];
int head[maxn],tol;
int pre[maxn];
double dist[maxn];
bool vis[maxn];
int N; //点数
void init(int n)
{
    N=n;
    tol=0;
    clr1(head);
}
void add(int u,int v,int cap,double cost)
{
    e[tol]=Edge(v,head[u],cap,cost);
    head[u]=tol++;
    e[tol]=Edge(u,head[v],0,-cost);
    head[v]=tol++;
}
bool spfa(int s,int t)
{
    queue<int>q;
    for(int i=0;i<=N;i++)
    {
        dist[i]=INF;
        vis[i]=false;
        pre[i]=-1;
    }
    dist[s]=0,vis[s]=true;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=false;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            if(e[i].cap&&dist[v]>dist[u]+e[i].cost)
            {
                dist[v]=dist[u]+e[i].cost;
                pre[v]=i;
                if(!vis[v]) vis[v]=true,q.push(v);
            }
        }
    }
    if(pre[t]==-1) return  false;
    return true;
}
void mincostflow(int s,int t,int &flow,int &cost)
{
    flow=cost=0;
    while(spfa(s,t))
    {
        int Min=INF;
        for(int i=pre[t];i!=-1;i=pre[e[i^1].to])
            if(Min>e[i].cap) Min=e[i].cap;
        for(int i=pre[t];i!=-1;i=pre[e[i^1].to])
            e[i].cap-=Min,e[i^1].cap+=Min,cost+=e[i].cost*Min;
        flow+=Min;
    }
}
int w[25];
int sc[25];
int a[45][25];
int fun(int x,int w)
{
    return (6400-3*(100-x)*(100-x))*w;
}
int main()
{
    int n,k,m;
    while(~scanf("%d%d%d",&n,&k,&m))
    {
        if(n==0&&k==0&&m==0) break;
        int sum=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&w[i]);
            sum+=w[i];
        }
        for(int i=1;i<=m;i++)
            scanf("%d",&sc[i]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&a[i][j]);
        int s=0,t=n+m+1;
        init(t+1);
        for(int i=1;i<=m;i++)
        {
            if(sc[i]<60)
                add(s,i,60-sc[i],-INF);
            int j=max(sc[i],60);
            int pre=fun(j,w[i]);
            for(j++;j<=100;j++)
            {
                int now=fun(j,w[i]);
                add(s,i,1,pre-now);
                pre=now;
            }
            for(j=1;j<=n;j++)
                if(a[j][i])
                    add(i,j+m,k,0);
        }
        for(int i=1;i<=n;i++)
            add(i+m,t,k,0);
        int flow,cost;
        mincostflow(s,t,flow,cost);
        for(int i=head[s];i!=-1;i=e[i].next)
            sc[e[i].to]+=e[i^1].cap;
        int ans=0,i;
        for(i=1;i<=m;i++)
        {
            if(sc[i]<60) break;
            ans+=fun(sc[i],w[i]);
        }
        if(i!=m+1) ans=0;
        printf("%.6lf\n",1.0*ans/sum/1600);
    }
    return 0;
}
时间: 2024-11-10 07:40:28

hdu4406 GPA 费用流的相关文章

HDU 4406 GPA(网络流-最大费用流)

GPA Problem Description GPA(Grade-Point Average) is one way to measure students' academic performance in PKU. Each course has an integer credit, ranges from 1 to 99. For each course, you will get a score at the end of the semester, which is an intege

【网络流24题】No.19 负载平衡问题 (费用流)

[题意] G 公司有 n 个沿铁路运输线环形排列的仓库, 每个仓库存储的货物数量不等. 如何用最少搬运量可以使 n 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入文件示例input.txt517 9 14 16 4 输出文件示例output.txt11 [分析] 其实我觉得这题可以贪心啊..n^2贪心??.没细想.. 打的是费用流.. 大概这样建图: 懒得写了..凌乱之美.. 求满流费用.. 1 #include<cstdio> 2 #include<cstdlib&

POJ 3422 kaka&#39;s matrix trvals(费用流)

#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <cma

hdu 2448 Mining Station on the Sea【网络费用流】

Mining Station on the Sea Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2371    Accepted Submission(s): 732 Problem Description The ocean is a treasure house of resources and the development

POJ训练计划3422_Kaka&#39;s Matrix Travels(网络流/费用流)

解题报告 题目传送门 题意: 从n×n的矩阵的左上角走到右下角,每次只能向右和向下走,走到一个格子上加上格子的数,可以走k次.问最大的和是多少. 思路: 建图:每个格子掰成两个点,分别叫"出点","入点", 入点到出点间连一个容量1,费用为格子数的边,以及一个容量∞,费用0的边. 同时,一个格子的"出点"向它右.下的格子的"入点"连边,容量∞,费用0. 源点向(0,0)的入点连一个容量K的边,(N-1,N-1)的出点向汇点连一

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)

[BZOJ3502]PA2012 Tanie linie Description n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. Sample Input 5 2 7 -3 4 -9 5 Sample Output 13 题解:跟1150和2151差不多. 我们先做一些预处理,因为连续的正数和连续的负数一定是要么都选要么都不选,所以可以将它们合并成一个数,同时区间中的零以及左右两端的负数没有意义,可以将它们删掉.然后我们得到的序列就变成:正-

POJ 2195 Going Home(费用流)

http://poj.org/problem?id=2195 题意: 在一个网格地图上,有n个小人和n栋房子.在每个时间单位内,每个小人可以往水平方向或垂直方向上移动一步,走到相邻的方格中.对每个小人,每走一步需要支付1美元,直到他走入到一栋房子里.每栋房子只能容纳一个小人. 计算出让n个小人移动到n个不同的房子需要支付的最小费用. 思路: 源点和每个人相连,容量为1,费用为0. 汇点和每栋房子相连,容量为1,费用为0. 每个人和每栋房子相连,容量为1,费用为人和房子之间的距离. 这样一来,跑一

洛谷P3381——费用流模板题

嗯..随便刷了一道费用流的模板题....来练练手. #include<iostream> #include<cstdio> #include<cstring> using namespace std; int h[5210],d[5210],used[5210],que[100010],last[5210]; int k=1,INF=0x7fffffff,ans1=0,ans2=0; inline int read(){ int t=1,num=0; char c=ge