AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1070

codevs上也有哦:http://codevs.cn/problem/2436/

 

这题感觉还是比较好想的。

因为算的是平均等待时间,那么就要考虑分配问题和顺序问题。

首先我们从s向每个汽车连容量为1,费用为0的边。

然后我们将师傅拆点,拆成n分,可以看做是倒数多少个的状态。

那么我们将每个汽车(i)向每个状态(j,k)都连一条容量为1,费用为k*w[j][i]的边。

表示师傅j在倒数第k个做i产生的贡献值。

然后再将每个状态往t连容量为1,费用为0的边。

跑最小费用最大流就可以了。

 

这题,因为连边多一点,所以zkw稍慢一点点:

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=65*65;
const int INF=0x3f3f3f3f;

struct Node{
    int data,next,low,cost;
}node[maxn*9*2];

#define www node[point].low
#define now node[point].data
#define ccc node[point].cost
#define then node[point].next

int n,m,cnt;
int s,t,ans;
int head[maxn],cur[maxn];
int dis[maxn];
int a[65][65];
bool vis[maxn];

void add(int u,int v,int w,int c){
    node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;node[cnt].cost=c;head[u]=cnt++;
    node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=0;node[cnt].cost=-c;head[v]=cnt++;
}

int dfs(int x,int low){
    if(x==t) return low;
    int Low;vis[x]=true;
    for(int &point=cur[x];point!=-1;point=then)
        if(www && !vis[now] && dis[x]==dis[now]+ccc){
            Low=dfs(now,min(low,www));
            if(Low){
                www-=Low,node[point^1].low+=Low;
                return Low;
            }
        }
    return 0;
}

bool modify(){
    int ad=INF;
    for(int i=s;i<=t;i++)
    if(vis[i])
        for(int point=head[i];point!=-1;point=then)
        if(www && !vis[now])
            ad=min(ad,dis[now]+ccc-dis[i]);
    if(ad==INF) return false;
    for(int i=s;i<=t;i++)
    if(vis[i])
        vis[i]=false,dis[i]+=ad;
    return true;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("1070.in","r",stdin);
    freopen("1070.out","w",stdout);
#endif

    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    t=n*(m+1)+1;
    for(int i=s;i<=t;i++) head[i]=-1;
    for(int i=1;i<=n;i++) add(s,i,1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=1;k<=n;k++)
                add(i,j*n+k,1,k*a[i][j]);
    for(int i=n+1;i<t;i++) add(i,t,1,0);
    
    int flag;
    do{
        for(int i=s;i<=t;i++) cur[i]=head[i];
        while(flag=dfs(s,INF))
            ans+=flag*dis[s];
    }while(modify());
    printf("%.2lf",(double)ans/n);
    return 0;
}
View Code

相关文章: