题意:要求改动公司数量最少并且效率最大(效率最大也就是最大完美匹配)
其中有一个最大的问题就是最少改变公司数量(也就是最少改变多少条边)
这个知识点我也是看了网上的,关于这个知识点我也感觉很神奇。除了这个问题其他的都是模版问题了。
可以把每条边的权值扩大k倍,并且k要大于n。
然后对原计划的边都+1。最小变动数量=N-加入原计划中的点数
模版一:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=105;
const int inf=0x3f3f3f3f;
int lx[maxn],ly[maxn];
int linker[maxn];
int visx[maxn],visy[maxn];
int w[maxn][maxn];
int slack[maxn];
int n,m;
int Find(int x){
visx[x]=1;
for(int y=1; y<=m; y++){
if(visy[y])continue;
int temp=lx[x]+ly[y]-w[x][y];
if(temp==0){
visy[y]=1;
if(!linker[y]||Find(linker[y])){
linker[y]=x;
return 1;
}
}else{
slack[y]=min(slack[y],temp);
}
}
return 0;
}
void KM(){
memset(linker,0,sizeof(linker));
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
lx[i]=max(lx[i],w[i][j]);
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=m;i++){
slack[i]=inf;
}
while(true){
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(Find(k))break;
int d=inf;
for(int i=1;i<=m;i++){
if(visy[i]==0){
d=min(slack[i],d);
}
}
if(d==inf)return ;
for(int i=1; i<=m; i++)
{
if(visx[i]) lx[i]-=d;
if(visy[i]) ly[i]+=d;
else
slack[i]-=d;
}
}
}
}
int main(){
int t,sum;
while(scanf("%d %d",&n,&m)!=EOF){
sum=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++){
scanf("%d",&w[i][j]);
w[i][j]*=66;
}
for(int i=1;i<=n;i++){
scanf("%d",&t);
w[i][t]++;
sum+=w[i][t];
}
KM();
int ans=0;
for(int i=1; i<=m; i++){
ans+=w[linker[i]][i];
}
cout<<(n-ans%66)<<" "<<(ans/66-sum/66)<<endl;
}
return 0;
}
模版二:超时
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxx=105;
const int inf=0x3f3f3f3f;
int n,m,w[maxx][maxx];
int mb[maxx],vb[maxx],ka[maxx],kb[maxx],p[maxx],c[maxx];
int qf,qb,q[maxx];
void Bfs(int u){
int a,v=0,vl=0,d;
for(int i=1;i<=n;i++) {
p[i]=0,c[i]=inf;
}
mb[v]=u;
do {
a=mb[v],d=inf,vb[v]=1;
for(int b=1;b<=n;b++)if(!vb[b]){
if(c[b]>ka[a]+kb[b]-w[a][b]){
c[b]=ka[a]+kb[b]-w[a][b];
p[b]=v;
}
if(c[b]<d) {
d=c[b];
vl=b;
}
}
for(int b=0;b<=n;b++){
if(vb[b]) {
ka[mb[b]]-=d;
kb[b]+=d;
}else {
c[b]-=d;
}
}
v=vl;
} while(mb[v]);
while(v) {
mb[v]=mb[p[v]];
v=p[v];
}
}
void init(){
memset(ka,0,sizeof(ka));
memset(kb,0,sizeof(kb));
memset(mb,0,sizeof(mb));
memset(p,0,sizeof(p));
memset(vb,0,sizeof(vb));
memset(c,0,sizeof(c));
memset(q,0,sizeof(q));
}
void KM(){
for(int a=1;a<=n;a++){
for(int b=1;b<=n;b++) {
vb[b]=0;
}
Bfs(a);
}
}
int main(){
int t,sum;
while(scanf("%d %d",&n,&m)!=EOF){
sum=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++){
scanf("%d",&w[i][j]);
w[i][j]*=66;
}
for(int i=1;i<=n;i++){
scanf("%d",&t);
w[i][t]++;
sum+=w[i][t];
}
KM();
int ans=0;
for(int i=1; i<=m; i++){
ans+=w[mb[i]][i];
}
cout<<(n-ans%66)<<" "<<(ans/66-sum/66)<<endl;
}
return 0;
}