当前位置:编程学习 > C/C++ >>

hdu3722Card Game(KM最大带权匹配)

题目大意:给n个字符串,再给一个n的排列:p1,p2....pn。然后将第i个字符串贴到第pi个字符串后面,然后形成一个环。pi的首字符和第i个字符串的末尾字符就相邻,如果这2个字符相等,各自再向内延伸一个位置,知道这个环首尾字符不等为止。延伸的位置为该环的得分(如果pi == i,得分为0),对于每个排列,有n个这样的环,求得分和最大为多少。
 
题目分析:最大带权匹配!!以为是个字符串的题目,就没仔细看。。。
 
建图直接跑模版。。。
 
详情请见代码:
 
 
#include <iostream>  
#include<cstdio>  
#include<cstring>  
using namespace std;  
const int N = 205;  
const int M = 1005;  
const int inf = 0x3f3f3f3f;  
char s[N][M];  
int n;  
int lx[N],ly[N],w[N][N];  
bool cx[N],cy[N];  
int match[N];  
int slack;  
int getw(int x,int y)  
{  
    int i,j;  
    i = strlen(s[x]) - 1;  
    j = 0;  
    int lenj = strlen(s[y]) - 1;  
    int ret = 0;  
    while(i >= 0 && j <= lenj && s[x][i] == s[y][j])  
        i --,j ++,ret ++;  
    return ret;  
}  
void predeal()  
{  
    int i,j;  
    for(i = 1;i <= n;i ++)  
    {  
        for(j = 1;j <= n;j ++)  
            if(i == j)  
                w[i][j] = 0;  
            else  
                w[i][j] = getw(i,j);  
    }  
}  
bool path(int u)  
{  
    cx[u] = true;  
    for(int v = 1;v <= n;v ++)  
    {  
        if(cy[v] == false)  
        {  
            int t = lx[u] + ly[v] - w[u][v];  
            if(t)  
            {  
                if(slack > t)  
                    slack = t;  
            }  
            else  
            {  
                cy[v] = true;  
                if(match[v] == -1 || path(match[v]))  
                {  
                    match[v] = u;  
                    return true;  
                }  
            }  
        }  
    }  
    return false;  
}  
void KM()  
{  
    int ans = 0;  
    int i,j;  
    for(i = 1;i <= n;i ++)  
    {  
        lx[i] = -inf;  
        ly[i] = 0;  
        for(j = 1;j <= n;j ++)  
            if(lx[i] < w[i][j])  
                lx[i] = w[i][j];  
    }  
    memset(match,-1,sizeof(match));  
    for(i = 1;i <= n;i ++)  
    {  
        while(1)  
        {  
            memset(cx,false,sizeof(cx));  
            memset(cy,false,sizeof(cy));  
            slack = inf;  
            if(path(i))  
                break;  
            for(j = 1;j <= n;j ++)  
            {  
                if(cx[j])  
                    lx[j] -= slack;  
                if(cy[j])  
                    ly[j] += slack;  
            }  
        }  
    }  
    for(i = 1;i <= n;i ++)  
        ans += w[match[i]][i];  
    printf("%d\n",ans);  
}  
int main()  
{  
    while(scanf("%d",&n) != EOF)  
    {  
        for(int i = 1;i <= n;i ++)  
            scanf("%s",s[i]);  
        predeal();  
        KM();  
    }  
    return 0;  
}  

 

 
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,