二分图匹配 Hdu3722

该博客探讨了如何利用二分图匹配理论和Kuhn-Munkres(KM)算法来解决字符串之间的费用最大化问题。通过计算字符串之间的费用,KM算法能有效地找到最优匹配,从而达到费用总和的最大化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意: 两个字符串之间可以计算出费用,然后用  KM算法 最大化这个费用和。。。

//KM算法求最大匹配
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define Maxn 210
#define INF 0x3f3f3f3f
int map[Maxn][Maxn],match[Maxn],slack[Maxn],lx[Maxn],ly[Maxn];
bool visx[Maxn],visy[Maxn];
int n,m;
bool dfs(int i){
	visx[i]=true;
	for (int j=1;j<=m;j++){
		if (visy[j]) continue;
		int tmp=lx[i]+ly[j]-map[i][j];
		if (tmp==0){
			visy[j]=true;
			if (match[j]==-1|| dfs(match[j])){
				match[j]=i;
				return true;
			}
		}
		else
		if (tmp<slack[j]) slack[j]=tmp;
	}
	return false;
}

int KM(){
	memset(match,-1,sizeof(match));
	memset(ly,0,sizeof(ly));
	for (int i=1;i<=n;i++){
		lx[i]=-INF;
		for (int j=1;j<=m;j++)
			lx[i]=max(lx[i],map[i][j]);
	}
	for (int k=1;k<=n;k++){
		for (int i=1;i<=m;i++) slack[i]=INF;
		while (1){
			memset(visx,false,sizeof(visx));
			memset(visy,false,sizeof(visy));
			if (dfs(k)) break;
			int dx=INF;
			for (int i=1;i<=m;i++)
				if (!visy[i]&&slack[i]<dx) dx=slack[i];
			for (int i=1;i<=n;i++)
				if (visx[i]) lx[i]-=dx;
			for (int i=1;i<=m;i++)
				if (visy[i]) ly[i]+=dx;
				else slack[i]-=dx;
		}
	}

	int ret=0;
	for (int i=1;i<=m;i++){
		ret+=map[match[i]][i];
	}
	return ret;
}
char s1[Maxn][1050],s2[Maxn][1050];
void reverse(char des[],char src[]){
	int len=strlen(src);
	for (int i=0;i<len;i++){
		des[i]=src[len-1-i];
	}
}
int main(){
	while (~scanf("%d",&n)){
		m=n;
		for (int i=1;i<=n;i++){
			scanf("%s",s1[i]);
			reverse(s2[i],s1[i]);
		}
		memset(map,0,sizeof(map));
		for (int i=1;i<=n;i++){
			for (int j=1;j<=n;j++)if (i!=j){
				int sum=0;
				int len=min(strlen(s1[i]),strlen(s2[j]));
				for (int k=0;k<len;k++){
					if (s1[i][k]==s2[j][k]) sum++;
					else break;
				}
				map[i][j]=sum;
			}
		}
		int ans=KM();
		printf("%d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值