标签:assignment hdu 2853 最大权匹配km
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
*/版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:assignment hdu 2853 最大权匹配km
原文地址:http://blog.csdn.net/u014422052/article/details/46773923