Assignment (HDU 2853 最大权匹配KM)


Assignment

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1068    Accepted Submission(s): 551


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
 

Recommend
gaojie   |   We have carefully selected several similar problems for you:  2855 2854 2856 2857 2858 


题意:n个公司m个任务。每一个公司仅仅接受一个任务。每一个任务仅仅被一个公司接受,每一个公司i接受任务j的做事效率为g[i][j],如今已经分配好了。问如何改变任务分配能够让效率最大,求出要修改的公司数目和添加的效率。

思路:与hdu3315相似,hdu 3315若点数为N,则把每条边的权值扩大x倍(x>N),若是原有匹配。则再把权值加1。最后KM算法求出ans,则最大权值之和=ans/x。没有被修改的=ans%x。

代码:


#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 1005
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b)  for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define DBG         pf("Hi\n")
typedef long long ll;
using namespace std;

/*
KM算法 O(nx*nx*ny)
求最大权匹配(最佳匹配)
若求最小权匹配,可将权值取相反数,结果取相反数
点的标号从0開始
*/

const int N=110;
int nx,ny;      //两边的点数
int g[N][N];    //二分图描写叙述,g赋初值为-INF
int linker[N],lx[N],ly[N];  //y 中各点匹配状态。x,y中的点的标号
int slack[N];
bool visx[N],visy[N];
bool flag;

bool DFS(int x)
{
    visx[x]=true;
    for (int y=0;y<ny;y++)
    {
        if (visy[y]) continue;
        int tmp=lx[x]+ly[y]-g[x][y];
        if (tmp==0)
        {
            visy[y]=true;
            if (linker[y]==-1||DFS(linker[y]))
            {
                linker[y]=x;
                return true;
            }
        }
        else if (slack[y]>tmp)
            slack[y]=tmp;
    }
    return false;
}

int KM()
{
    flag=true;
    memset(linker,-1,sizeof(linker));
    memset(ly,0,sizeof(ly));
    for (int i=0;i<nx;i++) //赋初值。lx置为最大值
    {
        lx[i]=-INF;
        for (int j=0;j<ny;j++)
        {
            if (g[i][j]>lx[i])
                lx[i]=g[i][j];
        }
    }
    for (int x=0;x<nx;x++)
    {
        for (int i=0;i<ny;i++)
            slack[i]=INF;
        while (true)
        {
            memset(visx,false,sizeof(visx));
            memset(visy,false,sizeof(visy));
            if (DFS(x)) break;
            int d=INF;
            for (int i=0;i<ny;i++)
                if (!visy[i]&&d>slack[i])
                    d=slack[i];
            for (int i=0;i<nx;i++)
                if (visx[i])
                    lx[i]-=d;
            for (int i=0;i<ny;i++)
            {
                if (visy[i])
                    ly[i]+=d;
                else
                    slack[i]-=d;
            }
        }
    }
    int res=0;
    for (int i=0;i<ny;i++)
    {
        if (linker[i]==-1||g[linker[i]][i]<=-INF) //有的点不能匹配的话return-1
        {
            flag=false;
            continue;
        }
        res+=g[linker[i]][i];
    }
    return res;
}
//记得nx和ny初始化!

!!!

!!

。! int n,m; int main() { #ifndef ONLINE_JUDGE freopen("C:/Users/asus1/Desktop/IN.txt","r",stdin); #endif int i,j,x; while (~sff(n,m)) { nx=n; ny=m; int sum=0; for (i=0;i<n;i++) for (j=0;j<m;j++) { sf(x); g[i][j]=x*100; } for (i=0;i<n;i++) { sf(x);x--; sum+=g[i][x]; g[i][x]++; } int ans=KM(); printf("%d %d\n",n-ans%100,ans/100-sum/100); } return 0; } /* 3 3 2 1 3 3 2 4 1 26 2 2 1 3 2 3 1 2 3 1 2 3 1 2 */



posted @ 2016-04-09 18:55  zfyouxi  阅读(203)  评论(0编辑  收藏  举报