当前位置:编程学习 > C/C++ >>

hdu 2853 Assignment (KM小变异)

Assignment
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 767    Accepted Submission(s): 410
 
 
Problem Description
Last year a terrible earthquake attacked Sichuan province. About 300,000 PLA soldiers attended the rescue, also ALPCs. Our mission is to solve difficulty problems to optimization the assignment of troops. The assignment is measure by efficiency, which is an integer, and the larger the better.
We have N companies of troops and M missions, M>=N. One company can get only one mission. One mission can be assigned to only one company. If company i takes mission j, we can get efficiency Eij. 
We have a assignment plan already, and now we want to change some companies’ missions to make the total efficiency larger. And also we want to change as less companies as possible.
 
 
Input
For each test case, the first line contains two numbers N and M. N lines follow. Each contains M integers, representing Eij. The next line contains N integers. The first one represents the mission number that company 1 takes, and so on.
1<=N<=M<=50, 1<Eij<=10000.
Your program should process to the end of file.
 
 
Output
For each the case print two integers X and Y. X represents the number of companies whose mission had been changed. Y represents the maximum total efficiency can be increased after changing.
 
 
Sample Input
3 3
2 1 3
3 2 4
1 26 2
2 1 3
2 3
1 2 3
1 2 3
1 2
 
 
Sample Output
2 26
1 2
 
 
Source
2009 Multi-University Training Contest 5 - Host by NUDT
 
 
题意:
给你一个图,给你一个匹配,让你在上面更改尽量少的匹配使匹配最大。
 
思路:
要满足权值相同时尽量选择以前的匹配,那么可以稍稍将以前的匹配的权值加一点喽,那么选择是就会优先选择以前的匹配了。具体方法是将所有边的权值都扩大K倍(k>n),将给你的匹配权值++,然后求出来的ans/k就是最大匹配了,ans%K就是有多少个原匹配没有改动了。
 
代码:
 
#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <algorithm>  
#include <cmath>  
#include <string>  
#include <map>  
#include <stack>  
#include <vector>  
#include <set>  
#include <queue>  
//#pragma comment (linker,"/STACK:102400000,102400000")  
#define maxn 205  
#define MAXN 1000005  
#define mod 1000000007  
#define INF 0x3f3f3f3f  
#define pi acos(-1.0)  
#define eps 1e-6  
typedef long long ll;  
using namespace std;  
  
int n,m,k,nx,ny,ans,sum;  
int link[maxn],lx[maxn],ly[maxn],slack[maxn]; //lx,ly为顶标,nx,ny分别为x点集y点集的个数  
int visx[maxn],visy[maxn],w[maxn][maxn];  
  
int DFS(int x)  
{  
    visx[x] = 1;  
    for (int y = 1;y <= ny;y ++)  
    {  
        if (visy[y]) continue;  
        int t = lx[x] + ly[y] - w[x][y];  
        if (t == 0)  
        {  
            visy[y] = 1;  
            if (link[y] == -1||DFS(link[y]))  
            {  
                link[y] = x;  
                return 1;  
            }  
        }  
        else if (slack[y] > t)  slack[y] = t;  
    }  
    return 0;  
}  
int KM()  
{  
    int i,j;  
    memset (link,-1,sizeof(link));  
    memset (ly,0,sizeof(ly));  
    for (i = 1;i <= nx;i ++)            //lx初始化为与它关联边中最大的  
        for (j = 1,lx[i] = -INF;j <= ny;j ++)  
            if (w[i][j] > lx[i])  
                lx[i] = w[i][j];  
    for (int x = 1;x <= nx;x ++)  
    {  
        for (i = 1;i <= ny;i ++)  
            slack[i] = INF;  
        while (1)  
        {  
            memset (visx,0,sizeof(visx));  
            memset (visy,0,sizeof(visy));  
            if (DFS(x)) break;  
            int d = INF;  
            for (i = 1;i <= ny;i ++)  
                if (!visy[i]&&d > slack[i])  
                    d = slack[i];  
            for (i = 1;i <= nx;i ++)  
                if (visx[i])  
                    lx[i] -= d;  
            for (i = 1;i <= ny;i ++)  //修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d  
                if (visy[i])  
                    ly[i] += d;  
                else  
                    slack[i] -= d;  
        }  
    }  
    int res = 0;  
    for (i = 1;i <= ny;i ++)  
        if (link[i] > -1)  
            res += w[link[i]][i];  
    return res;  
}  
int main()  
{  
    int i,j,t,x,y;  
    k=100;  
    while(~scanf("%d%d",&n,&m))  
    {  
        nx=n,ny=m;  
        for(i=1;i<=n;i++)  
        {  
            for(j=1;j<=m;j++)  
            {  
                scanf("%d",&w[i][j]);  
                w[i][j]*=k;  
            }  
        }  
        sum=0;  
        for(i=1;i<=n;i++)  
        {  
            scanf("%d",&t);  
            sum+=w[i][t]/k;  
            w[i][t]++;  
        }  
        ans=KM();  
        x=ans/k;  
        y=n-ans%k;  
        printf("%d %d\n",y,x-sum);  
    }  
}  

 

 
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,