pku The Windy's KM最小权匹配 or 最小费用最大流

http://poj.org/problem?id=3686

题意:

给定n个玩具,有m个车间,给出每个玩具在每个车间的加工所需的时间mat[i][j]表示第i个玩具在第j个车间加工所需的时间,规顶只有第i个玩具在j车间完成时第j车间才能接受其他玩具来生产。求加工完毕所有的的n个玩具所需的最小的平均时间。

思路:

不论使用KM求最小权匹配还是使用最小费用最大流求解,建图还是最重要的。笨啊...想不到啊。。

假设有n件玩具都在第j个车间生产,他们所需要的时间分别为T1 + 2*T1 + 3*T1 +..... + n*T1;  则第c个在j上的的所需时间为c*j,

我们将每个车间分成n个点,表示第i个可能是第几个在j车间上生产。然后求一个最小权匹配,或mcmf (这里注意好好计算边与点的数量);

KM:

View Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 2555
#define N 55
using namespace std;
//freopen("data.in","r",stdin);

int w[N][M],mat[N][N];
int lx[N],ly[M],slack[M];
bool vtx[N],vty[M];
int lk[M];
int n,m;

bool dfs(int i){
    vtx[i] = true;
    for (int j = 1; j <= m; ++j){
        if (vty[j]) continue;
        int tmp = lx[i] + ly[j] - w[i][j];
        if (tmp == 0){
            vty[j] = true;
            if (lk[j] == -1 || dfs(lk[j])){
                lk[j] = i;
                return true;
            }
        }
        else{
            slack[j] = min(slack[j],tmp);
        }
    }
    return false;
}
double KM(){
    int i,j;
    for (i = 1; i <= n; ++i){
        for (j = 1,lx[i] = -inf; j <= m; ++j){
            lx[i] = max(lx[i],w[i][j]);
        }
    }
    for (i = 1; i <= m; ++i){
        lk[i] = -1;
        ly[i] = 0;
    }
    for (i = 1; i <= n; ++i){
        for (j = 1; j <= m; ++j) slack[j] = inf;
        while (1){
            for (j = 1; j <= n; ++j) vtx[j] = false;
            for (j = 1; j <= m; ++j) vty[j] = false;
            if (dfs(i)) break;
            int d = inf;
            for (j = 1; j <= m; ++j){
                if (!vty[j]) d = min(d,slack[j]);
            }
            for (j = 1; j <= n; ++j){
                if (vtx[j]) lx[j] -= d;
            }
            for (j = 1; j <= m; ++j){
                if (vty[j]) ly[j] += d;
                else slack[j] -= d;
            }
        }
    }
    double sum = 0;
    for (i = 1; i <= m; ++i){
        if (lk[i] > -1) sum += w[lk[i]][i];
    }

    return (-sum);
}
int main(){
    //freopen("data.in","r",stdin);
    int i,j;
    int k;
    int T;
    scanf("%d",&T);
    while (T--){
        scanf("%d%d",&n,&m);
        for (i = 1; i <= n; ++i){
            for (j = 1; j <= m; ++j){
                scanf("%d",&mat[i][j]);
            }
        }
        CL(w,0);
        for (i =  1; i <= n; ++i){
            for (j = 1; j <= m; ++j){
                for (k = 1; k <= n; ++k){
                    w[i][(j - 1)*n + k] = -mat[i][j]*k;
                }
            }
        }
        m = n*m;

        double ans = KM()/(1.0*n);
       // printf("<>>>>>>>>>>>%d\n",m);
        printf("%.6lf\n",ans);
    }
    return 0;
}

 

mcmf:

View Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 127566
#define N 53
using namespace std;
//freopen("data.in","r",stdin);


struct node{
    int v;
    int w,c;
    int next;
}g[M*2];
int head[N*N],ct;
int mat[N][N];
int pre[M],dis[M];
int path[M];
bool vt[M];
int n,m;

void spfa(int s,int e){
    int i;
    for (i = s; i <= e; ++i){
        dis[i] = inf;
        pre[i] = -1;
        vt[i] = false;
        path[i] = 0;
    }
    pre[s] = s; dis[s] = 0;
    vt[s] = true;
    queue<int>q;
    q.push(s);
    while (!q.empty()){
        int u = q.front(); q.pop();
        for (int i = head[u]; i != -1; i = g[i].next){
            int v = g[i].v;
            int w = g[i].w;
            int ci = g[i].c;
            if (dis[v] > dis[u] + w && ci > 0){
                 dis[v] = dis[u] + w;
                 pre[v] = u;
                 path[v] = i;
                 if (!vt[v]){
                    q.push(v);
                    vt[v] = true;
                 }
            }
        }
        vt[u] = false;
    }
}
double mcmf(int s,int e){
    double ans = 0;
    int i;
    while (1){
        spfa(s,e);
        if (pre[e] == -1) break;

        int MIN = inf;
        for (i = e; i != s; i = pre[i]){
            MIN = min(MIN,g[path[i]].c);
        }
        for (i = e; i != s; i = pre[i]){
            g[path[i]].c -= MIN;
            g[path[i]^1].c += MIN;
            ans += MIN*g[path[i]].w;
        }
    }
    return ans;
}
void add(int u,int v,int c,int w){
    g[ct].v = v;
    g[ct].c = c;
    g[ct].w = w;
    g[ct].next = head[u];
    head[u] = ct++;
}


int main(){
   //freopen("data.in","r",stdin);
    int i,j,T;
    int k;
    scanf("%d",&T);
    while (T--){
        CL(head,-1); ct = 0;
        scanf("%d%d",&n,&m);
        for (i = 1; i <= n; ++i){
            for (j = 1; j <= m; ++j){
                scanf("%d",&mat[i][j]);
            }
        }

        for (i = 1; i <= n; ++i){
            for (j = 1; j <= m; ++j){
                for (k = 1; k <= n; ++k){
                    int tp = j*n + k;
                    add(i,tp,1,mat[i][j]*k);
                    add(tp,i,0,-mat[i][j]*k);


                    /*c[i][tp] = 1; c[tp][i] = 0;
                    w[i][tp] = mat[i][j]*k;
                    w[tp][i] = -mat[i][j]*k;*/
                }
            }
        }
        int s = 0 , e = (m + 1)*n + 1;
        for (i = 1; i <= n; ++i){
             add(s,i,1,0); add(i,s,0,0);

            /*c[s][i] = 1; c[i][s] = 0;
            w[s][i] = w[i][s] = 0;*/
        }
        for (i = n + 1; i <= (m + 1)*n; ++i){
            add(i,e,1,0); add(e,i,0,0);

            /*c[i][e] = 1; c[e][i] = 0;
            w[i][e] = w[e][i] = 0;*/
        }

        printf("%.6lf\n",mcmf(s,e)/n);
    }
    return 0;
}

 

 

 

posted @ 2012-11-01 23:00  E_star  阅读(292)  评论(0编辑  收藏  举报