hdu3718Similarity KM算法

来源:互联网 发布:java乘法表代码阶梯 编辑:程序博客网 时间:2024/06/05 01:58
//n个物品,用字母表示每个物品的种类,//给出标准答案对于每种物品的字母表示//给出每个人的答案,问怎样的匹配使得两个答案的相似度更高//{A A B A B B C C C C},{F F E F E E D D D D}表示一种答案//对每个字母和字母之间建图,两个答案在同一个位置的字母之间的边的权值加1//那么就只需要求其最大带权匹配#include<cstdio>#include<cstring>#include<iostream>using namespace std ;const int maxn = 10100 ;const int inf = 0x3f3f3f3f ;int w[30][30] ;int idx[30] , idy[30] ;int match[30] ;char str[maxn][10] ;   int n , m , k;int lx[30] , ly[30] ;int visx[30] , visy[30] , slack[30] ;bool find(int x){    visx[x] = 1 ;    for(int i = 1;i <= k;i++)    {        if(visy[i]) continue ;        int tmp = lx[x] + ly[i] - w[x][i] ;        if(tmp == 0)        {            visy[i] = 1 ;            if(match[i] == -1 || find(match[i]))            {               match[i] = x;              return true ;             }        }        else slack[i] = min(slack[i] , tmp) ;    }    return false ;}int KM(){    memset(match , -1 , sizeof(match)) ;    memset(ly , 0 ,sizeof(ly)) ;    for(int i = 1;i <= k;i++)    {        lx[i] = -inf ;        for(int j = 1;j <= k;j++)        lx[i] = max(lx[i] , w[i][j]) ;    }    for(int i = 1;i <= k;i++)    {        for(int j = 1;j <= k;j++)        slack[j] = inf ;        while(1)        {            memset(visx , 0 , sizeof(visx)) ;            memset(visy , 0 , sizeof(visy)) ;            if(find(i))break;            int d = inf ;            for(int j = 1 ;j <= k;j++)            if(!visy[j])            d = min(d , slack[j]) ;            for(int j = 1;j <= k;j++)            if(visx[j])              lx[j] -= d ;            for(int j = 1 ;j <= k;j++)            if(visy[j])              ly[j] += d ;            else             slack[j] -= d ;        }    }    int ans = 0 ;    for(int i  =1;i <= k;i++)    ans += w[match[i]][i] ;    return ans ;}int main(){   // freopen("in.txt" ,"r" , stdin) ;    int T ;    scanf("%d" ,&T) ;    while(T--)    {        scanf("%d%d%d" , &n , &k , &m) ;        memset(idx , 0 , sizeof(idx)) ;        int len = 0 ;        for(int i = 1;i <= n;i++)        {            scanf("%s"  ,str[i]);            if(!idx[str[i][0]-'A'])            idx[str[i][0]-'A'] = ++len ;        }        while(m--)        {            char ch[3] ;            memset(w , 0 , sizeof(w)) ;            memset(idy , 0 ,sizeof(idy)) ;            len = 0 ;            for(int i = 1;i <= n;i++)            {                scanf("%s" , ch) ;                if(!idy[ch[0]-'A'])idy[ch[0]-'A'] = ++len ;                w[idx[str[i][0]-'A']][idy[ch[0]-'A']]++ ;            }            int ans = KM() ;            printf("%.4lf\n" , (double)ans/(double)n) ;        }    }    return 0 ;}
0 0
原创粉丝点击