bzoj 1070: [SCOI2007]修车

题目链接

bzoj:1070: [SCOI2007]修车

题解

假设一个大叔修了k辆车,修的第i个车的车主等待时间是自己车被修的时间的与前边\(i-1\)辆车修车时间的和
它对答案的贡献就是\(x_i*(k-i+1)\)
把大叔拆成n个点,每一层点代表该时刻,顾客连向大叔们,流连为,费用为\((k-层数+1)*等待时间\)
ps ~~n,m看反狂 WA 4次ORZ

代码

// luogu-judger-enable-o2
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::min;
using std::queue;
const int maxn = 10;
const int maxm = 35007;
inline int read() {
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x;
}
int n,m;
int peo[70][10];
struct node{
    int u,v,next,flow,cost;
}edge[maxm<<1];
int num=1,head[maxm];
void add_edge(int u,int v,int flow,int cost)  {
    edge[++num].v=v;edge[num].u=u;edge[num].next=head[u];edge[num].flow=flow;edge[num].cost=cost;head[u]=num;
    edge[++num].v=u;edge[num].u=v;edge[num].next=head[v];edge[num].flow=0;edge[num].cost=-cost;head[v]=num;
}
int dis[maxm<<1],pre[maxm<<1];bool vis[maxm<<1];
int S=0,T;
bool spfa() {
    memset(dis,0x3f,sizeof dis);
    vis[S]=1;dis[S]=0;
    queue<int>que;
    que.push(S);
    while(!que.empty()) {
        int u=que.front();
        que.pop();
        for(int i=head[u];i;i=edge[i].next) {
            int v=edge[i].v;
            if(edge[i].flow&&dis[u]+edge[i].cost<dis[v]) {
                dis[v]=edge[i].cost+dis[u];
                pre[v]=i;
                if(!vis[v]) 
                    que.push(v),vis[v]=1;
            }
        }
        vis[u]=0;
    }
    if(dis[T]!=0x3f3f3f3f)return true;
    else return false;
}
int calc() {
    int ret=0;
    int maxx = 0x3f3f3f3f;
    for(int i=T;i!=S;i=edge[pre[i]].u)
        maxx=min(edge[pre[i]].flow,maxx);
    for(int i=T;i!=S;i=edge[pre[i]].u) {
        edge[pre[i]].flow-=maxx;
        edge[pre[i]^1].flow+=maxx;
        ret+=maxx*edge[pre[i]].cost;
    }
    return ret;
}
int ans=0;
void mcfc() {
    while(spfa())
        ans+=calc();
}
int main() {
    m=read(),n=read();
    T=n+n*m+1;  	
    for(int i=1;i<=n;++i) {
        for(int j=1;j<=m;++j) {
            peo[i][j]=read();
        }
    }
    for(int i=1;i<=n;++i) add_edge(S,i,1,0);
    for(int i=1;i<=m;++i) {
        for(int j=1;j<=n;++j) {
            add_edge(n*i+j,T,1,0);
        }
    }
    for(int i=1;i<=n;++i) 
        for(int j=1;j<=m;++j) 
            for(int k=1;k<=n;++k) 
                add_edge(i,n*j+k,1,k*peo[i][j]);
    mcfc();
    printf("%.2lf\n",(double)ans/n);
    return 0;
}

posted @ 2018-02-06 21:44  zzzzx  阅读(93)  评论(0编辑  收藏  举报