hdu 4406 GPA(最大费用流)

来源:互联网 发布:陶瓷内胆有毒吗 知乎 编辑:程序博客网 时间:2024/04/29 12:43

题意:距离考试有n天,现在有m个科目要复习,每天能有k个复习时间单元,每用一个时间单元复习,就能让所复习的科目分数增加一分,在保证不挂科的情况下,让绩点尽量高……


思路:这题除了费用的问题外,建图还是比较直观的,添加一个源点S和汇点T,每一天向T连一条容量为k,费用为0的弧,每个科目向对应能复习的天连一条容量为k,费用为0的弧,剩下就是S向科目连对应的弧。首先,为了保证不挂科,如果第i科基础分数小于60分,那么就从S向i连一条容量为60-分数,费用为inf的弧,这样在执行费用流的时候会优先填满这些弧,对于其他的分数x,我们可以算出x+1时增加的绩点,设f(x)为x对应的绩点的话,可以算一下f(x+1)-f(x),发现这是个减函数,因此,我们只需要对应会增加的分数,每一分连一条容量为1,费用为f(x)-f(x-1)的弧就好了。最后做一下最大费用流,其实这样建图也不会有环,因此费用取反做最小费用流也一样,最后检查一下是否还是有科目会挂就好了。


代码:


#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<set>#include<stack>#include<cmath>#include<vector>#define inf 0x3f3f3f3f#define Inf 0x3FFFFFFFFFFFFFFFLL#define eps 1e-9#define pi acos(-1.0)using namespace std;typedef long long ll;const int maxn=100+10;const int maxm=4000+10;struct Edge{    int from,to,cap,flow,next;    double cost;    Edge(){};    Edge(int ff,int tt,int cc,int fl,double co,int nx)    {from=ff;to=tt;cap=cc;flow=fl;cost=co;next=nx;}}edges[maxm<<1];int head[maxn],a[maxn],p[maxn],nEdge;bool inq[maxn];double d[maxn];void AddEdges(int from,int to,int cap,double cost){    edges[++nEdge]=Edge(from,to,cap,0,cost,head[from]);    head[from]=nEdge;    edges[++nEdge]=Edge(to,from,0,0,-cost,head[to]);    head[to]=nEdge;}bool spfa(int s,int t,int &flow,double &cost){    memset(inq,0,sizeof(inq));    memset(d,0,sizeof(d));    a[s]=inf;p[s]=0;    queue<int>q;    q.push(s);    while(!q.empty())    {        int u=q.front();q.pop();        inq[u]=false;        for(int k=head[u];k!=-1;k=edges[k].next)        {            Edge e=edges[k];            if(e.cap>e.flow&&d[e.to]<d[u]+e.cost)            {                d[e.to]=d[u]+e.cost;                a[e.to]=min(a[u],e.cap-e.flow);                p[e.to]=k;                if(!inq[e.to]){inq[e.to]=true;q.push(e.to);}            }        }    }    if(d[t]==0) return false;    flow+=a[t];    cost+=a[t]*d[t];    int u=t;    while(u!=s)    {        edges[p[u]].flow+=a[t];        edges[p[u]^1].flow-=a[t];        u=edges[p[u]].from;    }    return true;}void mincost(int s,int t){    int flow=0;double cost=0;    while(spfa(s,t,flow,cost)) ;}int basicp[maxn],w[maxn],matrix[maxn][maxn],res[maxn];double getpoint(int i,int x){    return (4.0-3.0*(100-x)*(100-x)/1600.0)*w[i];}double solve(int S,int m){    double ans=0;    memset(res,0,sizeof(res));    for(int k=head[S];k!=-1;k=edges[k].next)    {        Edge e=edges[k];        res[e.to]+=e.flow;    }    for(int i=1;i<=m;++i)    {        res[i]+=basicp[i];        if(res[i]<60) return 0;        ans+=getpoint(i,res[i]);    }    return ans;}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int n,k,m;    while(~scanf("%d%d%d",&n,&k,&m))    {        if(n==0&&k==0&&m==0) break;        memset(head,0xff,sizeof(head));        nEdge=-1;        for(int i=1;i<=m;++i)            scanf("%d",&w[i]);        for(int i=1;i<=m;++i)            scanf("%d",&basicp[i]);        for(int i=1;i<=n;++i)            for(int j=1;j<=m;++j)                scanf("%d",&matrix[i][j]);        int S=0,T=n+m+1,sum=0;        for(int i=1;i<=m;++i)        {            if(basicp[i]<60) AddEdges(S,i,60-basicp[i],1e6);            int j=max(basicp[i],60)+1;            for(;j<=100;++j)                AddEdges(S,i,1,getpoint(i,j)-getpoint(i,j-1));            for(j=1;j<=n;++j)                if(matrix[j][i]) AddEdges(i,m+j,k,0);            sum+=w[i];        }        for(int i=1;i<=n;++i)            AddEdges(m+i,T,k,0);        mincost(S,T);        double ans=solve(S,m)/sum;        printf("%.6lf\n",ans);    }    return 0;}

0 0
原创粉丝点击