BZOJ1070
费用流。
源点连到n辆车,容量为1,费用为0
把每个工人拆成n个点,对于第j个工人第p个点,表示该工人 倒数 第p个完成该任务的代价,因为你现在做的任务不会影响到你的前几个任务,只会给后面添加代价,所以n辆车连到这些点,容量为1,代价为map[i][j]*p
这些点再连到汇点,容量为1,代价为0
最后注意下数组一定要足够大
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define min(u1,u2) (u1<u2?u1:u2)
int map[1000][1000];
struct mod{int x,y,c,d,next,other;};
mod q[100000];
int first[10005];
int s[10000];
int t[10000];
bool vis[10000];
int pre[10000],pi[10000];
int maxx=1000000000;
int len=0,ans=0;
int S,T;
void ins(int x,int y,int c,int d)
{
len++;
q[len].x=x;
q[len].y=y;
q[len].c=c;
q[len].d=d;
q[len].next=first[x];
first[x]=len;
q[len].other=len+1;
len++;
q[len].x=y;
q[len].y=x;
q[len].c=0;
q[len].d=-d;
q[len].next=first[y];
first[y]=len;
q[len].other=len-1;
}
bool spfa()
{
memset(s,63,sizeof(s));
s[S]=0;
memset(vis,false,sizeof(vis));
vis[S]=true;
t[1]=S;
int st=1,ed=2;
while(st!=ed)
{
int x=t[st];
for (int i=first[x];i!=-1;i=q[i].next)
{
int y=q[i].y;
if (q[i].c>0&&s[x]+q[i].d<s[y])
{
s[y]=s[x]+q[i].d;
pre[y]=x;
pi[y]=i;
if (vis[y]==false)
{
vis[y]=true;
t[ed]=y;
ed++;
if (ed>T)ed=1;
}
}
}
vis[x]=false;
st++;
if (st>T)st=1;
}
if (s[T]>10000000)return false;
return true;
}
int fond()
{
ans=0;
while(spfa())
{
//for (int i=1;i<=len;i++)
//printf("i:%d x:%d y:%d c:%d d:%d\n",i,q[i].x,q[i].y,q[i].c,q[i].d);
//system("pause");
int minn=100000000;
for (int i=T;i!=S;i=pre[i])
minn=min(minn,q[pi[i]].c);
int o=minn*s[T];
ans+=o;
//printf("s:%d\n",s[T]);
for (int i=T;i!=S;i=pre[i])
{
q[pi[i]].c-=minn;
q[q[pi[i]].other].c+=minn;
}
}
return ans;
}
int main()
{
int n,m;
memset(first,-1,sizeof(first));
scanf("%d%d",&m,&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
scanf("%d",&map[i][j]);
}
S=0;
T=n+n*m+1;
for (int i=1;i<=n;i++)
ins(S,i,1,0);
for (int i=n+1;i<T;i++)
ins(i,T,1,0);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
for (int k=1;k<=n;k++)
{
ins(i,j*n+k,1,(n-k+1)*map[i][j]);
}
double nn=(double)fond();
printf("%.2lf\n",nn/n);
}