UVAlive 6129 最小权匹配

题意:给你N个工人和N个工作,每个工作分为2个部分,必须先完成这个工作的第一部分,才能再做第二部分。每个工人分别完成一个工作的上下部分,不能完成两个工作的同一部分。

最后输出每个工人完成的工作的部分,和总时间。

最后输出一个等待的时间。

思路:

分两次进行匹配,先对每个工作的第一部分进行匹配,做一次最小权匹配,然后对于第二部分,我们进行建图的时候就要注意,当前工作的上部分是否已经完成,所以假设我们要做第二部分工作的时候,i -> j ,那么先求出i完成第一部分的时间,然后求出j工作在第一部分被完成的时间。然后两者取最大值,加上j工作在第二部分被i完成的时间,就是i ->j的第二部分的权值。

然后再做一遍匹配就可以了。

CODE:

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )

using namespace std;

inline void RD(int &ret) {
    char c;
    int flag = 1 ;
    do {
        c = getchar();
        if(c == '-')flag = -1 ;
    } while(c < '0' || c > '9') ;
    ret = c - '0';
    while((c=getchar()) >= '0' && c <= '9')
        ret = ret * 10 + ( c - '0' );
    ret *= flag ;
}

inline void OT(int a) {
    if(a >= 10)OT(a / 10) ;
    putchar(a % 10 + '0') ;
}

inline void RD(double &ret) {
    char c ;
    int flag = 1 ;
    do {
        c = getchar() ;
        if(c == '-')flag = -1 ;
    } while(c < '0' || c > '9') ;
    ll n1 = c - '0' ;
    while((c = getchar()) >= '0' && c <= '9') {
        n1 = n1 * 10 + c - '0' ;
    }
    ll n2 = 1 ;
    while((c = getchar()) >= '0' && c <= '9') {
        n1 = n1 * 10 + c - '0' ;
        n2 *= 10 ;
    }
    ret = flag * (double)n1 / (double)(n2) ;
}
/*********************************************/
#define N 55
int a[N][N] ;
int b[N][N] ;
int n ;
int Map[N][N] ;
int lx[N] , ly[N] , visx[N] , visy[N] , linky[N] ,linkx[N] ;
int slx[N] ,sly[N] , slinky[N] , slinkx[N] ;
int firstsolve[N] ;
int gap[N][N] ;
int find(int now){
    visx[now] = 1 ;
    for (int i = 1 ; i <= n ; i ++ ){
        if(!visy[i]){
            int fk = Map[now][i] - lx[now] - ly[i] ;
            if(!fk){
                visy[i] = 1 ;
                if(linky[i] == -1 || find(linky[i])){
                    linky[i] = now ;
                    linkx[now] = i ;
                    return 1 ;
                }
            }
        }
    }
    return 0 ;
}
int KM(){
    mem(linky ,-1) ;
    mem(linkx, -1) ;
    mem(ly ,0) ;
//    bug ;
    for (int i = 1 ; i <= n ; i ++ ){
//        bug ;
        while(1){
            mem(visx, 0) ;mem(visy ,0) ;
            if(find(i))break ;
//            bug ;
            int d = inf ;
            for (int j = 1 ; j <= n ; j ++ )
                if(visx[j])
                    for (int k = 1 ; k <= n ; k ++ )
                        if(!visy[k])
                            d = min(d , Map[j][k] - lx[j] - ly[k]) ;
            for (int j = 1 ; j <= n ; j ++ ){
                if(visx[j])lx[j] += d ;
                if(visy[j])ly[j] -= d ;
            }
        }
    }
    int ans = 0 ;
    for (int i = 1 ; i <= n ; i ++ ){
        if(linky[i] != -1)ans += Map[linky[i]][i] ;
    }
    return ans ;
}
int main() {
    int ca = 0 ;
    while(cin >> n , n){
        for (int i = 1 ; i <= n ; i ++ ){
            for (int j = 1 ; j <= n ; j ++ ){
                cin >> a[i][j] ;
            }
        }
        for (int i = 1 ; i <= n ; i ++ ){
            for (int j = 1 ; j <= n ; j ++ ){
                cin >> b[i][j] ;
            }
        }
        for (int i = 1 ; i <= n ; i ++ ){
            lx[i] = inf ;
            for (int j = 1 ; j <= n ; j ++ ){
                Map[i][j] = a[i][j] ;
                lx[i] = min(lx[i] , a[i][j]) ;
            }
        }
        int ans1 = KM() ;
//        for (int i = 1 ; i <= n ; i ++ ){
//            cout << i << " " << linkx[i] << " " << Map[i][linkx[i]] << endl;
//        }
//        cout << endl;
        for (int i = 1 ; i <= n ; i ++ ){
            firstsolve[i] = lx[i] + ly[linkx[i]] ;
        }
        for (int i = 1 ; i <= n ; i ++ ){
            slx[i] = lx[i] ; sly[i] = ly[i] ; slinky[i] = linky[i] ; slinkx[i] = linkx[i] ;
//            firs
        }
        mem(gap ,0) ;
//        cout << Map[1][2] << " hrer" << endl;
//        cout << slinky[2] << " hrere" << endl;
        for (int i = 1 ; i <= n ; i ++ ){
            lx[i] = inf ;
            for (int j = 1 ; j <= n ; j ++ ){
                int tx = slx[i] + sly[linkx[i]] ;
                int ty = a[slinky[j]][j] ;
                int tt = max(tx , ty) ;//求出两者的最大值。
                if(ty > tx){
                    gap[i][j] = ty - tx ;//记录两点的差值,即工人等待的时间。
                }
                Map[i][j] = tt + b[i][j] ;
                lx[i] = min(lx[i] , Map[i][j]) ;
            }
        }
        int ans2 = KM() ;
        int sum = 0 ;
        printf("Case %d:\n", ++ ca) ;
        for (int i = 1 ; i <= n ; i ++ ){
            printf("Worker %d: ",i) ;
            cout << slinkx[i] << " " << linkx[i] << " " << Map[i][linkx[i]] << endl ;
            sum += gap[i][linkx[i]] ;
        }
        printf("Total idle time: %d\n",sum) ;
    }
    return 0 ;
}


/*
4
8 6 12 19
13 2 18 10
9 15 16 17
5 18 4 10
2 6 3 3
8 5 9 2
5 8 4 3
4 4 5 2
0

*/


你可能感兴趣的:(UVAlive 6129 最小权匹配)