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
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.
1<=N<=M<=50, 1<Eij<=10000.
Your program should process to the end of file.
3 3 2 1 3 3 2 4 1 26 2 2 1 3 2 3 1 2 3 1 2 3 1 2
2 26 1 2
题意: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
*/
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号