HDU2853(最大权完美匹配)

题意:要求改动公司数量最少并且效率最大(效率最大也就是最大完美匹配)
其中有一个最大的问题就是最少改变公司数量(也就是最少改变多少条边)
这个知识点我也是看了网上的,关于这个知识点我也感觉很神奇。除了这个问题其他的都是模版问题了。

可以把每条边的权值扩大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;
}
上一篇:【ybtoj 高效进阶 3.2】【最小生成树】 新的开始


下一篇:2021-05-05