BZOJ1070 [SCOI2007]修车 最小费用最大流

构造一个图,左边nmn∗m个点,表示第jj个技术人员修的倒数第ii辆车,右边nn个点,表示第kk辆车

  源点向左边的点连(w=1,cost=0)(w=1,cost=0)的边,因为每个人同一时刻只能修一辆车

  左边mnm∗n个点再分别向右边nn个点连边,左边第(i,j)(i,j)个点向右边第kk个点连(w=INF,cost=it[i][j])(w=INF,cost=i∗t[i][j])的边

  相当于此时有ii个人在等待着这辆车修完,代价就是等待的人数∗修这辆车的时间

  右边的点向汇点连(w=1,cost=0)(w=1,cost=0)的边,表示每辆车只能被一个人修

  容易看出,此时最大流一定是nn,每一条w=1w=1的流表示第jj个人修的倒数第ii辆车是第kk辆车

  那么最小费用除以nn就是我们的答案

 

我写的代码一直TLE....

本地过了就是过了,OJ上TLE是OJ有问题

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 10000;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;
struct Edge{
        int to,next,cap,flow,cost;
} edge[MAXM];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N;

void init(){
        tol = 0;
        memset(head, - 1,sizeof(head));
}

void addedge(int u,int v,int cap,int cost){
        edge[tol].to = v;
        edge[tol].cap = cap;
        edge[tol].cost = cost;
        edge[tol].flow = 0;
        edge[tol].next = head[u];
        head[u] = tol++;
        edge[tol].to = u;
        edge[tol].cap = 0;
        edge[tol].cost = - cost;
        edge[tol].flow = 0;
        edge[tol].next = head[v];
        head[v] = tol++;
}

bool spfa(int s,int t){
        queue<int>q;
        memset(dis,INF,sizeof(dis));
        memset(vis,false,sizeof(vis));
        memset(pre,-1,sizeof(pre));
        dis[s] = 0;
        vis[s] = true;
        q.push(s);
        while(!q.empty()){
                int u = q.front();
                q.pop();
                vis[u] = false;
                for(int i = head[u]; i != - 1; i = edge[i].next){
                        int v = edge[i].to;

                        if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost ){
                                dis[v] = dis[u] + edge[i].cost;
                                pre[v] = i;
                                if(!vis[v]){
                                        vis[v] = true;
                                        q.push(v);
                                }
                        }
                }
        }
        if(pre[t] == - 1)
                return false;
        else
                return true;
}

int minCostMaxflow(int s,int t,int &cost){
        int flow = 0;
        cost = 0;
        while(spfa(s,t)){
                int Min = INF;
                for(int i = pre[t]; i != - 1; i = pre[edge[i^1].to]){
                        if(Min > edge[i].cap - edge[i].flow)
                                Min = edge[i].cap - edge[i].flow;
                }
                for(int i = pre[t]; i != - 1; i = pre[edge[i^1].to]){
                        edge[i].flow += Min;
                        edge[i^1].flow -= Min;
                        cost += edge[i].cost * Min;
                }
                flow += Min;
        }
        return cost;
}

int n,m;
int car[70][70],id_man[70][70],id_car[70];
int cnt,s,t;
int main()
{
    cnt = 0;
    scanf("%d%d",&m,&n);
    for (int i = 1;i <= n;++i){
        for (int j = 1;j <= m;++j){
            scanf("%d",&car[i][j]);
        }
    }
    init();
    s = cnt++;t = cnt++;
    for (int i = 1;i <= m;++i){
        for (int j = 1;j <= n;++j){
            addedge(s,id_man[i][j] = cnt++,1,0);
        }
    }
    for (int i = 1;i <= n;++i){
        addedge(id_car[i] = cnt++,t,1,0);
    }
    for (int i = 1;i <= m;++i){//第i个人
        for (int j = 1;j <= n;++j){//倒数第j次
            for (int k = 1;k <= n;++k){//车k
                addedge(id_man[i][j],id_car[k],1,j*car[k][i]);
            }
        }
    }
    N = cnt;
    int cost = 0;
    printf("%.2f\n",(double)minCostMaxflow(s,t,cost)/n);
}

 

下面是别人的AC代码

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 10 + 5;
const int M = 60 + 5;
const int INF = 0x3f3f3f3f;

int n, m;
int S, T, cnt;
int C[N][M], id1[N][M], id2[M];

int head[N * M], len;
struct nodeLib {
    int to, nxt, val, flow;
    inline void add(int a, int b, int c, int d) {
        to = b, val = d, flow = c;
        nxt = head[a], head[a] = len++;
    }
} lib[N * M * M << 1];

inline int read() {
    char ch;
    int ans = 0, neg = 1;
    while (ch = getchar(), ch < '0' || ch > '9')
        if (ch == '-') neg = -1;
    while (ch >= '0' && ch <= '9')
        ans = ans * 10 + ch - '0', ch = getchar();
    return ans * neg;
}

inline void makePath(int a, int b, int c, int d) {
    lib[len].add(a, b, c, d);
    lib[len].add(b, a, 0, -d);
}
void init() {
    n = read(), m = read();
    len = 2, S = ++cnt, T = ++cnt;
    for (int j = 1; j <= m; j++)
        for (int i = 1; i <= n; i++)
            C[i][j] = read();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            makePath(S, id1[i][j] = ++cnt, 1, 0);
    for (int i = 1; i <= m; i++)
        makePath(id2[i] = ++cnt, T, 1, 0);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            for (int k = 1; k <= m; k++)
                makePath(id1[i][j], id2[k], 1, j * C[i][k]);
}

queue <int> Q;
bool inQ[N * M];
int dist[N * M], preE[N * M], preV[N * M];
bool SPFA() {
    memset(dist, 0x3f, sizeof(dist));
    dist[S] = 0, Q.push(S), inQ[S] = true;
    while (!Q.empty()) {
        int tmp = Q.front();
        Q.pop(), inQ[tmp] = false;
        for (int p = head[tmp]; p; p = lib[p].nxt) {
            int now = lib[p].to, val = lib[p].val;
            if (lib[p].flow && dist[now] > dist[tmp] + val) {
                dist[now] = dist[tmp] + val;
                preE[now] = p, preV[now] = tmp;
                if (!inQ[now]) Q.push(now), inQ[now] = true;
            }
        }
    }
    return dist[T] != INF;
}
int MCMF() {
    int ans = 0;
    while (SPFA()) {
        int maxf = INF;
        for (int p = T; p != S; p = preV[p])
            maxf = min(maxf, lib[preE[p]].flow);
        for (int p = T; p != S; p = preV[p])
            lib[preE[p]].flow -= maxf, lib[preE[p] ^ 1].flow += maxf;
        ans += dist[T] * maxf;
    }
    return ans;
}

int main() {
    init();
    printf("%.2lf\n", (double)MCMF() / m);
    return 0;
}

 

posted @ 2018-08-28 15:17  mizersy  阅读(131)  评论(0编辑  收藏  举报