题意:
有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; }