欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HDU 3718 Similarity(二分图最大匹配问题)

程序员文章站 2024-03-19 21:53:22
...

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3718

题目意思:有两串字符串,他们都是分类的结果.第一行是正确结果,第二行是需要你判断的.比如:

       A A B A B B C C C C

       S T R S T R S T  R S

       当S对应A,T对应B,R对应C时, 它们匹配的位置个数=4

       当S对应C,T对应A,B对应R时, 它们匹配的位置个数=5

       明显第二种匹配方式更好,字符串相似率达到了5/10=50%.

       现在给你很多字符串,要你输出最大相似率.

这题难在了建图上,参考了大佬的题解https://blog.csdn.net/discreeter/article/details/50331785,可以以每对对应字母建立边关系,遍历学生的答案和正确答案,得到边的权值,然后利用二分图的KM算法,套模板,得出最大匹配权值,最后输出最大匹配权值/字符串长度 即相似率.

关于KM算法参考这两个大佬的博客:1 http://www.cnblogs.com/wenruo/p/5264235.html     2   https://www.cnblogs.com/logosG/p/logos.html

贴上AC代码:

// ProblemN.cpp: 定义控制台应用程序的入口点。
//

//#include "stdafx.h"
#include<iostream>
#include<cstring>
#include<algorithm>
#include<iomanip>
using namespace std;
const int INF = 0x3f3f3f3f;
char s1[10010], s2[10010];
int line[60][60], link[60], slack[60], fx[60], fy[60];
bool visx[60], visy[60];

int n, m, k;

bool Find(int x)
{
	visx[x] = true;
	for (int i = 0; i < 26; i++)
	{
		if (visy[i])continue;
		int gap = fx[x] + fy[i] - line[x][i];
		if (gap == 0)
		{
			visy[i] = true;
			if (link[i] == -1 || Find(link[i]))
			{
				link[i] = x;
				return true;
			}
			
		}
		else
			{
				slack[i] = min(slack[i], gap);
			}
	}
	return false;
}

int KM()
{
	memset(link, -1, sizeof(link));
	memset(fy, 0, sizeof(fy));
	for (int i = 0; i < 26; i++)
	{
		fx[i] = line[i][0];
		for (int j = 1; j < 26; j++)
		{
			fx[i] = max(fx[i], line[i][j]);
		}
	}

	for (int i = 0; i < 26; i++)
	{
		fill(slack, slack + 26, INF);
		while (true)
		{
			memset(visx, 0, sizeof(visx));
			memset(visy, 0, sizeof(visy));
			if (Find(i))break;
			int d = INF;
			for (int j = 0; j < 26; j++)
			{
				if (!visy[j])
					d = min(d, slack[j]);
			}
			for (int j = 0; j < 26; j++)
			{
				if (visx[j])
					fx[j] -= d;
				if (visy[j])
					fy[j] += d;
				else
				{
					slack[j] -= d;
				}
			}
		}
	}
	int res = 0;
	for (int i = 0; i < 26; i++)
		res += line[link[i]][i];
	return res;
}
int main()
{
	int t;
	while (cin >> t)
	{
		while (t--)
		{
			cin >> n >> k >> m;
			for (int i = 0; i < n; i++)
				cin >> s1[i];
			for (int i = 0; i<m; i++)
			{
				for (int j = 0; j < n; j++)
					cin >> s2[j];
				memset(line, 0, sizeof(line));
				for (int j = 0; j < n; j++)
					line[s2[j] - 'A'][s1[j] - 'A']++;//建图,遍历两个字符串,得到权值
				double ans = 1.0*KM() / n;
				cout << fixed << setprecision(4) << ans << endl;
			}
		}
	}
	return 0;
}

                                                                           

相关标签: e