程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HDU Assignment(KM變形好題!!!!)

HDU Assignment(KM變形好題!!!!)

編輯:C++入門知識



Assignment


題目鏈接:Click Here~

題目分析:

給出n個人m個任務(n<=m),要你給每個人分配任務,每個人對每個任務都有一個效益。要求你求出n個人的最大效益。且一開始每個人手上都有一個任務,你在以後分配任務的時候,必須更換盡量少的任務使得每個人的任務效益最大。


算法分析:

一道顯然的二分匹配算法。用KM求出最大的效益就好了。


建模分析:

因為,在更換最少的任務前提下的最大效益。所以,我們可以把每個任務擴大K倍(K>n)。為了使得盡量保持原先分配的任務,所以要給原先分配的任務+1。為什麼這樣可以呢?因為,前面我們擴大了K倍了,且K>n。所以,實質+1這個只對原先相等的權值有作用的,這就是為什麼要K>n的原因。最後,在把結果除以K,就是結果。總結點減去結果求余K就是改變的數。為什麼呢?因為有數學知識知道原先的每個權值都乘以了一個K。所以,不是原先分配的任務都可以被K除盡,唯一剩下的就是原先分配剩下的那個+1的值。


ACM果然是個一群高智商的人,玩的蛋疼游戲!!!


#include 
#include 
#include 
#include 
using namespace std;

const int MAXN = 50 + 5;
const int INF = ~0U>>1;
const int K = MAXN+MAXN;
int n,m,W[MAXN][MAXN];
int slack,Lx[MAXN],Ly[MAXN],Link[MAXN];
bool S[MAXN],T[MAXN];
inline bool Match(int i)
{
    S[i] = true;
    for(int j = 1;j <= m;++j)if(!T[j]){
        int tmp = Lx[i]+Ly[j]-W[i][j];
        if(tmp==0){
            T[j] = true;
            if(Link[j]==-1||Match(Link[j])){
                Link[j] = i;
                return true;
            }
        }
        else if(tmp < slack)
            slack = tmp;
    }
    return false;
}
inline void Update(int d)
{
    for(int i = 1;i <= n;++i)
        if(S[i]) Lx[i] -= d;
    for(int j = 1;j <= m;++j)
        if(T[j]) Ly[j] += d;
}
bool EK()
{
    for(int i = 1;i <= n;++i){
        Lx[i] = 0;
        for(int j = 1;j <= m;++j)
            Lx[i] = max(Lx[i],W[i][j]);
    }
    memset(Link,-1,sizeof(Link));
    memset(Ly,0,sizeof(Ly));

    slack = INF;
    for(int i = 1;i <= n;++i){
        while(1){
            memset(S,false,sizeof(S));
            memset(T,false,sizeof(T));
            if(Match(i))
                break;
            if(slack==INF)
                return false;
            Update(slack);
        }
    }
    return true;
}
void Get(int& X,int& Y)
{
    int sum = 0;
    for(int i = 1;i <= m;++i){
        if(Link[i]!=-1)
            sum += W[Link[i]][i];
    }
    Y = sum/K - Y;
    X = n - sum%K;
}
int main()
{
//    freopen("Input.txt","r",stdin);
//    freopen("Out.txt","w",stdout);
    while(~scanf("%d%d",&n,&m))
    {
        memset(W,0,sizeof(W));
        for(int i = 1;i <= n;++i){
            for(int j = 1;j <= m;++j){
                scanf("%d",&W[i][j]);
                W[i][j] *= K;
            }
        }
        int x,X,Y = 0;
        for(int i = 1;i <= n;++i){
            scanf("%d",&x);
            Y += W[i][x]/K;
            W[i][x]++;
        }
        EK();
        Get(X,Y);
        printf("%d %d\n",X,Y);
    }
    return 0;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved