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


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
2.757813 0.000000
题意:有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;
}
原文:http://blog.csdn.net/neko01/article/details/40779983