Similarity HDU 3718||UVALive

来源:互联网 发布:淘宝试用报名技巧 编辑:程序博客网 时间:2024/05/21 00:14

传送门:HDU3718

题意:

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

       A A B A B B C C CC

       S T R S T R S T RS

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

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

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

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

(以上借鉴自http://blog.csdn.net/u013480600/article/details/38760375)

思路:典型的二分图匹配问题,一开始还以为是最大匹配,结果怎么调试都不对,后来发现每条边应该是有权值的,比如上面的例子,第一个字母为A-S,则A->S的边权值++,以此类推,最后跑一遍KM就好了。

PS:神坑点是用getchar()的话会超时。。

代码:

#include<bits/stdc++.h>using namespace std;const int MAXN=30;const int inf=0x3f3f3f3f;int vn,un;int g[MAXN][MAXN];map<char,int>s1,s2;char p[11111],q[11111];int linker[MAXN],lx[MAXN],ly[MAXN];bool visx[MAXN],visy[MAXN];int slack[MAXN];bool dfs(int x){visx[x]=1;for(int y=0;y<vn;y++){if(visy[y])continue;int tmp=lx[x]+ly[y]-g[x][y];if(tmp==0){visy[y]=1;if(linker[y]==-1||dfs(linker[y])){linker[y]=x;return true;}}else if(slack[y]>tmp){slack[y]=tmp;}}return false;}int KM(){int res=0;memset(ly,0,sizeof(ly));memset(linker,-1,sizeof(linker));for(int i=0;i<un;i++){lx[i]=-inf;for(int j=0;j<vn;j++){if(g[i][j]>lx[i]){lx[i]=g[i][j];}}}for(int x=0;x<un;x++){for(int i=0;i<vn;i++)slack[i]=inf;while(true){memset(visx,0,sizeof(visx));memset(visy,0,sizeof(visy));if(dfs(x))break;int d=inf;for(int i=0;i<vn;i++){if(!visy[i]&&d>slack[i]){d=slack[i];}}for(int i=0;i<un;i++){if(visx[i])lx[i]-=d;}for(int i=0;i<vn;i++)if(visy[i])ly[i]+=d;else slack[i]-=d;}}for(int i=0;i<vn;i++)if(linker[i]!=-1)res+=g[linker[i]][i];return res;}int main(){int t,n,m,k;char c;scanf("%d",&t);while(t--){int cnt=0;scanf("%d%d%d",&n,&k,&m);un=vn=26;getchar();for(int i=0;i<n;i++){scanf(" %c",&p[i]);}while(m--){memset(g,0,sizeof(g));for(int i=0;i<n;i++){scanf(" %c",&q[i]);g[p[i]-'A'][q[i]-'A']++;}printf("%.4lf\n",KM()*1.0/n);}}}


0 0
原创粉丝点击