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;
}
上一篇: 网络分析工具-Mtr
下一篇: 硬币变化问题