题意:
有N个任务和M个机器,给出第i个任务在第j个机器完成的时间map[i][j],每台机器同一时刻只能处理一个任务,机器必须完整地完成一个任务后才能接着完成下一个任务。问N个任务完成时间的平均值最少为多少。
关键:
设N个任务的执行时间分别为T1,T2…TN,则N个订单的总的执行时间是
T1*N + T2*(N-1) + … + TN-1*2 + TN。
构图:
将每台机器拆成N个点。第k个点表示倒数第k个完成的任务。将任务i和机器j的第k个分点连权值为map[i][j]*k的边。
总点数:N+M*N+2;
总边数:(N+N*M+N*N*M)*2;
PS.这题是比较好的构图题。虽然费用流效率比较低可是目前还没看过KM,只好用费用流了。
构图代码:
void Init()//构图
{
int i,j,k;
memset(head,-1,sizeof(head));ecnt=0;
scanf("%d%d",&N,&M);
scr=0;sink=N+M*N+1;vn=sink+1;
for(i=1;i<=N;i++)
Insert(scr,i,1,0);
for(i=N+1;i<=M*N+N;i++)
Insert(i,sink,1,0);
for(i=1;i<=N;i++)
{
for(j=1;j<=M;j++)
{
scanf("%d",&map[i][j]);
//Insert(i,j+N,1,map[i][j]);
}
}
for(i=1;i<=N;i++)
{
int cnt=N+1;
for(j=1;j<=M;j++)
{
for(k=1;k<=N;k++)
{
Insert(i,cnt++,1,map[i][j]*k);
}
}
}
}
CODE:
/*最小费用流+拆点*/
/*AC代码:969ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <queue>
#define MAXN 2600
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define INF 1e8
using namespace std;
struct edge
{
int u,v,w,c,next;
}E[800000];
int head[MAXN],ecnt;
bool vis[MAXN];
int dis[MAXN],pre[MAXN];
int map[55][55];
int N,M,scr,sink,vn;
void Insert(int u,int v,int w,int c)
{
E[ecnt].u=u;
E[ecnt].v=v;
E[ecnt].w=w;
E[ecnt].c=c;
E[ecnt].next=head[u];
head[u]=ecnt++;
E[ecnt].u=v;
E[ecnt].v=u;
E[ecnt].w=0;
E[ecnt].c=-c;
E[ecnt].next=head[v];
head[v]=ecnt++;
}
void Init()//构图
{
int i,j,k;
memset(head,-1,sizeof(head));ecnt=0;
scanf("%d%d",&N,&M);
scr=0;sink=N+M*N+1;vn=sink+1;
for(i=1;i<=N;i++)
Insert(scr,i,1,0);
for(i=N+1;i<=M*N+N;i++)
Insert(i,sink,1,0);
for(i=1;i<=N;i++)
{
for(j=1;j<=M;j++)
{
scanf("%d",&map[i][j]);
//Insert(i,j+N,1,map[i][j]);
}
}
for(i=1;i<=N;i++)
{
int cnt=N+1;
for(j=1;j<=M;j++)
{
for(k=1;k<=N;k++)
{
Insert(i,cnt++,1,map[i][j]*k);
}
}
}
}
queue<int>Q;
bool SPFA(int s,int t,int n)
{
int i,u,v,c;
memset(vis,false,sizeof(vis));
for(i=0;i<=n;i++)
dis[i]=INF;
Q.push(s);
pre[s]=-1;
dis[s]=0;
vis[s]=true;
while(!Q.empty())
{
//printf("^\n");
u=Q.front();Q.pop();
vis[u]=false;
for(i=head[u];i!=-1;i=E[i].next)
{
v=E[i].v;c=E[i].c;
if(E[i].w>0&&dis[v]>dis[u]+c)//前提是E[i].w>0
{
dis[v]=dis[u]+c;
pre[v]=i;
if(!vis[v])
{
vis[v]=true;
Q.push(v);
}
}
}
}
if(dis[t]<INF) return true;
return false;
}
void Solve()
{
int i,u,v,du,dv,ans=0,flow;
while(SPFA(scr,sink,vn))
{
//printf("*\n");
ans+=dis[sink];
for(i=pre[sink];i!=-1;i=pre[E[i].u])//更新容量
{
E[i].w--;
E[i^1].w++;
}
}
double res=ans*1.0/N;
printf("%.6lf\n",res);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
Init();
Solve();
}
return 0;
}