HDU 4406 最大费用最大流

题意:现有m门课程需要复习,已知每门课程的基础分和学分,共有n天可以复习,每天分为k个时间段,每个时间段可以复习一门课程,并使这门课程的分数加一,问在不挂科的情况下最高的绩点。

思路:(没做过费用流的转这里:http://www.cnblogs.com/L-King/p/5316359.html),首先我们得保证每门课程都达到60分,所以对每一门未到60分的课程添加一条从S(即源点)出发的弧,容量为60-该课程的分数,花费为INF,因此在执行费用流的时候会优先增广此弧。此时,我们已经保证了在条件允许的情况下,每门课程都达到60分以上。接下来就是剩下的分数的分配,设f(x)为x对应的p;可解得f(x)以及f‘(x)都是减函数(x>=60),即f(x+1)-f(x)<f(x)-f(x-1),因此可以对每一分连接一条容量为1,费用为f(x)-f(x-1)的弧。最后就是每门课程与对应的天连接一条容量为k,费用为0的弧,每一天与T(即汇点)连接一条容量为k,费用为0的弧。最后跑一下费用流,然后判断是否有课程未达到60分。

代码:

#include<stdio.h>
#include<string.h>
#define min(x,y) (x)<(y)?(x):(y)

const int N=111,M=44444,INF=0x3f3f3f3f;
struct node
{
    int u,v,c,next;
    double w;
}e[M];
int head[N],q[M],p[N],pre[N];
int s,t,l,r,cnt;
double d[N];
int w[N],b[N],f[N];
void add(int u,int v,int c,double w)
{
    e[cnt].u=u,e[cnt].v=v,e[cnt].c=c,e[cnt].w=w;
    e[cnt].next=head[u],head[u]=cnt++;
    e[cnt].u=v,e[cnt].v=u,e[cnt].c=0,e[cnt].w=-w;
    e[cnt].next=head[v],head[v]=cnt++;
}
void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
}

int spfa()
{
    int i,u,v;
    double w;
    memset(pre,-1,sizeof(pre));
    memset(p,0,sizeof(p));
    memset(f,0,sizeof(f));
    for(i=0;i<=t;i++)    d[i]=-1.0*INF;
    l=r=0;d[s]=0;f[s]=INF;q[++r]=s;
    while(l<r)
    {
        p[u=q[++l]]=0;
        for(i=head[u];i!=-1;i=e[i].next)
        {
            v=e[i].v,w=e[i].w;
            if(e[i].c&&d[v]<d[u]+w)
            {
                d[v]=d[u]+w;
                f[v]=min(f[u],e[i].c);
                pre[v]=i;
                if(!p[v])
                {
                    q[++r]=v;
                    p[v]=1;
                }
            }
        }
    }
    return f[t];
}

double getp(int x,int w)
{
    return (4.0-3.0*(100-x)*(100-x)/1600)*w;
}
void MicMaf()
{
    int m;
    while(m=spfa())
    {
        for(int i=pre[t];i!=-1;i=pre[e[i].u])
        {
            e[i].c-=m;
            e[i^1].c+=m;
        }
    }
}
int main()
{
    int n,m,k,i,j,x;
    while(scanf("%d%d%d",&n,&k,&m),n||m||k)
    {
        init();s=0,t=n+m+1;
        for(i=1;i<=m;i++)    scanf("%d",&w[i]);
        for(i=1;i<=m;i++)    scanf("%d",&b[i]);
        for(i=1;i<=n;i++)
        {
            add(i+m,t,k,0);
            for(j=1;j<=m;j++)
            {
                scanf("%d",&x);
                if(x)    add(j,i+m,k,0);
            }
        }
        double pre,cur;
        for(i=1;i<=m;i++)
        {
            if(b[i]<60)
            {
                add(s,i,60-b[i],1.0*INF);
                pre=getp(60,w[i]);
                for(j=61;j<=100;j++)
                {
                    cur=getp(j,w[i]);
                    add(s,i,1,cur-pre);
                    pre=cur;
                }
            }
            else
            {
                pre=getp(b[i],w[i]);
                for(j=b[i]+1;j<=100;j++)
                {
                    cur=getp(j,w[i]);
                    add(s,i,1,cur-pre);
                    pre=cur;
                }
            }
        }
        MicMaf();
        for(i=head[s];i!=-1;i=e[i].next)
            b[e[i].v]+=e[i^1].c;
        int sum=0;double ans=0;
        for(i=1;i<=m;i++)
            sum+=w[i];
        for(i=1;i<=m;i++)
        {
            if(b[i]<60)    break;
            ans+=getp(b[i],w[i])/sum;
        }
        if(i<=m)    ans=0;
        printf("%.6f\n",ans);
    }
    return 0;
}

参考文章:http://www.cnblogs.com/jianglangcaijin/archive/2012/10/06/2713375.html

     http://www.xuebuyuan.com/2064806.html

时间: 2024-10-05 03:51:49

HDU 4406 最大费用最大流的相关文章

hdu 2516 最小费用最大流

原来这个代码超时 #include<stdio.h> #include<queue> #include<string.h> using namespace std; #define N 200 #define inf 0x3fffffff int cap[N][N]; int fee[N][N]; int s,t,sum,pre[N]; int spfa() { queue<int>q; int dis[N],visit[N],u,i; memset(pre

hdu 1533(最小费用最大流)

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4223    Accepted Submission(s): 2178 Problem Description On a grid map there are n little men and n houses. In each unit time, every l

多校第一场:HDU 4862 最小费用最大流

思路:这题主要是建图搞了好久,以前没判断过满流,所以又看了这个知识点,然后才发现自己的最小费用最大流在求满流的时候有bug,正好改了过来. 建图:开始看题解知道这题是最小费用最大流,然后没看解释就做了.然后自己建的图没得求出答案,然后想了好久也没发现哪里错.然后看了官方题解,发现自己的建图和官方差太大了.可能是受昨天做POJ最小费用建图的影响吧.官方的建太符合题目意思了,只能说,我还看了好久建图才理解的. 构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,流量1,费用0:Y部有N*M个

hdu 3667(最小费用最大流+拆边)

Transportation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2670    Accepted Submission(s): 1157 Problem Description There are N cities, and M directed roads connecting them. Now you want to

【网络流#2】hdu 1533 最小费用最大流模板题

嗯~第一次写费用流题... 这道就是费用流的模板题,找不到更裸的题了 建图:每个m(Man)作为源点,每个H(House)作为汇点,各个源点与汇点分别连一条边,这条边的流量是1(因为每个源点只能走一条边到汇点),费用是 从源点走到汇点的步数,因为有多个源点与汇点,要建一个超级源点与超级汇点,超级源点与各个源点连一条流量为1,费用为0(要避免产生多余的费用)的边 按照这个图跑一发费用流即可 把代码挂上去,用的是前向星写的 1 #include<cstdio> 2 #include<cstr

HDU 1533 最小费用最大流(模板)

http://acm.hdu.edu.cn/showproblem.php?pid=1533 这道题直接用了模板 题意:要构建一个二分图,家对应人,连线的权值就是最短距离,求最小费用 要注意void init(int n) 这个函数一定要写 一开始忘记写这个WA了好几发 还有这个题很容易T掉,赋值建图要简化,一开始构建成网络流那种图一直T #include <stdio.h> #include <string.h> #include <iostream> #includ

Matrix (hdu 2686 最大费用最大流)

Matrix Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1893    Accepted Submission(s): 1006 Problem Description Yifenfei very like play a number game in the n*n Matrix. A positive integer numbe

hdu 6437 /// 最小费用最大流 负花费 SPFA模板

题目大意: 给定n,m,K,W 表示n个小时 m场电影(分为类型A.B) K个人 若某个人连续看了两场相同类型的电影则失去W 电影时间不能重叠 接下来给定m场电影的 s t w op 表示电影的 开始时间s 结束时间t 看完这场电影则获得w 电影类型是op(0为A 1为B) 将一场电影拆成两个点 s t,两点间连线花费为-w容量为1 源点与所有电影的s点连线 花费为0容量为1 所有电影的t点与汇点连线 花费为0容量为1 若两场电影的时间不冲突 那么按时间顺序在之间连边 若类型相同 花费为W容量为

hdu4322 最大费用最大流

http://acm.hdu.edu.cn/showproblem.php?pid=4322 Problem Description There are N candies and M kids, the teacher will give this N candies to the M kids. The i-th kids for the j-th candy has a preference for like[i][j], if he like the sugar, like[i][j]