zoukankan      html  css  js  c++  java
  • poj

    题意:n个订单和m个生产车间,每个订单在不同的车间生产所需要的时间不一样,并且每个订单只能在同一个车间中完成,直到这个车间完成这个订单就可以生产下一个订单.现在需要求完成n个订单的平均时间最少是多少.(每个订单的单独时间之和/n,包括等待时间)。

    主要是建图,考虑第i个订单在第j个车间倒数第k个被生产,那么第i个订单在第j个区间所花费的时间为k*mat[i][j].

    每个区间最多生产n个订单,那么就可以把n*m的图转化成n*(n*m)的图进而用km算法求最小权值。

    所以把每个权值取反进而求最大权匹配,但是为什么不能直接求最小权匹配还是没想清楚.

    注意G++用%f输出,否则wa.

    参考:http://www.tuicool.com/articles/jmYNryf

     1 #include<iostream>
     2 #define max(a,b) ((a)>(b)?(a):(b))
     3 #define min(a,b) ((a)<(b)?(a):(b))
     4 using namespace std;
     5 const int nMax = 52;
     6 const int mMax = 2502;
     7 const int inf = 99999999;
     8  
     9 int n, m;                     //  n为X集合顶点数量,m为Y集合顶点数量。(1~n和1~m)
    10 int map[nMax][mMax];          //  map[i][j]:记录X集合中的i到Y集合中的j所需的费用。
    11 int lx[nMax], ly[mMax];
    12 int link[mMax];
    13 bool x[nMax], y[mMax];
    14  
    15 bool dfs(int u){              //  判断能否找到最大完全匹配。
    16     x[u] = true;
    17     for(int v = 1; v <= m; v ++)
    18         if(!y[v] && lx[u] + ly[v] == map[u][v]){
    19             y[v] = true;
    20             if(!link[v] || dfs(link[v])){
    21                 link[v] = u;
    22                 return true;
    23             }
    24         }
    25     return false;
    26 }
    27  
    28 int KM(){                     //  KM算法。
    29     int i, j, k, mi;
    30     for(i = 1; i <= n; i ++)
    31         for(lx[i] = -inf, j = 1; j <= m; j ++)
    32             lx[i] = max(lx[i], map[i][j]);
    33     memset(ly, 0, sizeof(ly));
    34     memset(link, 0, sizeof(link));
    35     for(k = 1; k <= n; k ++){
    36         while(1){
    37             memset(x, 0, sizeof(x));
    38             memset(y, 0, sizeof(y));
    39             if(dfs(k)) break;
    40             mi = inf;
    41             for(i = 1; i <= n; i ++)
    42                 if(x[i])
    43                     for(j = 1; j <= m; j ++)
    44                         if(!y[j])
    45                             mi = min(mi, lx[i] + ly[j] - map[i][j]);
    46             for(i = 1; i <= n; i ++) if(x[i]) lx[i] -= mi;
    47             for(i = 1; i <= m; i ++) if(y[i]) ly[i] += mi;
    48         }
    49     }
    50     int ans = 0;
    51     for(i = 1; i <= m; i ++)
    52         if(link[i] > 0)
    53             ans += map[link[i]][i];
    54     return ans;
    55 }
    56  
    57 int main(){
    58     int t, N, M, i, j, k, mat[nMax][nMax];
    59     scanf("%d", &t);
    60     while(t --){
    61         scanf("%d%d", &N, &M);
    62         for(i = 1; i <= N; i ++)
    63             for(j = 1; j <= M; j ++)
    64                 scanf("%d", &mat[i][j]);
    65         n = N, m = N * M;
    66         for(i = 1; i <= N; i ++)         //  KM算法是求最大权,故这里存负数,最后取反求最小权。
    67             for(j = 1; j <= N; j ++)
    68                 for(k = 1; k <= M; k ++){
    69                     map[i][(k-1)*N+j] = -j*mat[i][k];
    70                     //cout << i << ' ' << (k-1)*N+j << ' ' << j*mat[i][k] << endl;
    71                 }
    72         double ans = 1.0*(-KM())/N;      //  精度必须取double才AC。
    73         printf("%.6f
    ", ans);
    74     }
    75     return 0;
    76 }

    这题还可以用费用流来解决.不过效率没有KM高.

    初始源点和每个订单相连,每个车间拆成n*m个车间,然后和汇点相连.然后和km考虑的一样在订单和车间之间连边.

     1 #include<cstdio>
     2 #include<queue>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 const int maxn = 2550;
     7 const int INF = 1e9;
     8 struct edge{
     9     int to,next;
    10     int cap,flow,cost;
    11 }e[maxn*maxn];
    12 int n,m;
    13 int head[maxn],sz,res;
    14 bool inq[maxn];
    15 int p[maxn],d[maxn],a[maxn];
    16 void addedge(int u,int v,int cap,int cost){
    17     e[sz].to = v;e[sz].next = head[u];
    18     e[sz].cap = cap;e[sz].flow = 0;e[sz].cost = cost;
    19     head[u] = sz ++;
    20     e[sz].to = u;e[sz].next = head[v];
    21     e[sz].cap = 0;e[sz].flow = 0;e[sz].cost = -cost;
    22     head[v] = sz ++;
    23 }
    24 void init(){
    25     memset(head,-1,sizeof(head));
    26     sz = 0;
    27 }
    28 queue<int> Q;
    29 int SPFA(int s,int t){
    30     memset(inq,0,sizeof(inq));
    31     for(int i = 0 ; i <= t ; i ++) d[i] = INF;
    32     inq[s] = 1;d[s] = 0;p[s] = -1;
    33     a[s] = INF;
    34     Q.push(s);
    35     while(!Q.empty()){
    36         int u = Q.front();Q.pop();
    37         inq[u] = 0;
    38         for(int i = head[u] ; i != -1 ; i = e[i].next){
    39             int v = e[i].to;
    40             if(e[i].cap - e[i].flow > 0 && e[i].cost + d[u] < d[v]){
    41                 d[v] = d[u] + e[i].cost;
    42                 a[v] = min(e[i].cap - e[i].flow,a[u]);
    43                 p[v] = i;
    44                 if(!inq[v]){
    45                     inq[v] = 1;
    46                     Q.push(v);
    47                 }
    48             }
    49         }
    50     }
    51     int u = t;
    52     if(d[t] == INF) return 0;
    53     res += d[t] * a[t];
    54     while(u != s){
    55         e[ p[u] ].flow += a[t];
    56         e[ p[u] ^ 1 ].flow -= a[t];
    57         u = e[ p[u] ^ 1 ].to;
    58     }
    59     return 1;
    60 }
    61 
    62 void MCMF(int s,int t){
    63     res = 0;
    64     while(SPFA(s,t));
    65     printf("%.6f
    ",res*1.0/n);
    66 }
    67 
    68 void solve(){
    69     init();
    70     int s,t,mat[55][55];
    71     scanf("%d%d",&n,&m);
    72     s = 0;t = n * m + n + 1;
    73     for(int i=1;i<=n;i++)
    74         for(int j=1;j<=m;j++)
    75         scanf("%d",&mat[i][j]);
    76     for(int i = 1; i <= n; i ++)
    77     {
    78         addedge(s,i,1,0);
    79         for(int j = 1; j <= n; j ++)
    80         {
    81             for(int k = 1; k <= m; k ++)
    82             {
    83                 addedge(i,n+(k-1)*n+j,1,j*mat[i][k]);
    84             }
    85         }
    86     }
    87     for(int i=n+1;i<=n*m+n;i++)
    88         addedge(i,t,1,0);
    89     MCMF(s,t);
    90 }
    91 int main()
    92 {
    93    //freopen("a.txt","r",stdin);
    94     int t;
    95     scanf("%d",&t);
    96     while(t--) solve();
    97     return 0;
    98 }
  • 相关阅读:
    vector与iterator的一些用法
    动态规划 hdu 1024
    dfs bfs hdu 1045
    hdu 2795
    poj 2828
    线段树染色
    线段树比大小
    A
    ?线程局部变量
    JRE、JDK、JVM 及 JIT
  • 原文地址:https://www.cnblogs.com/nowandforever/p/4701643.html
Copyright © 2011-2022 走看看