HDU 3722 Card Game(KM最大匹配)

本文通过一道典型题目介绍了KM算法的应用及其实现过程。针对比赛中遇到的问题,详细解释了如何正确建立图模型,并给出了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题就是一道KM算法的模版题,下午做比赛的时候两个模版都是TLE,好不科学,比赛结束后去杭电交就成WA了,更不科学……后来发现是建图的时候写挫了T_T,要不比赛的时候就能多出一题了,还有一道匹配题也没敢写,一会就去写一下。话说根本不知道KM的实现啊,只知道抄模版,感觉自己好挫啊……

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
#define MAX 205
#define INF 9999999
int n,match[MAX];
bool sx[MAX],sy[MAX];
char str[MAX][1005];
int lx[MAX],ly[MAX],map[MAX][MAX];
bool path(int u)
{
    sx[u]=true;
    for(int v=0;v<n;v++)
        if(!sy[v]&&lx[u]+ly[v]==map[u][v])
        {
            sy[v]=true;
            if(match[v]==-1||path(match[v]))
            {
                match[v]=u;
                return true;
            }
        }
        return false;
}
int KM(bool truth)//可以不用更改地处理最小或最大权匹配
{
    int i,j;
    if(!truth)
    {
        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
                map[i][j]=-map[i][j];
    }
    for(i=0;i<n;i++)
    {
        lx[i]=-INF;
        ly[i]=0;
        for(j=0;j<n;j++)
            if(lx[i]<map[i][j])
                lx[i]=map[i][j];
    }
    memset(match,-1,sizeof(match));
    for(int u=0;u<n;u++)
        while(1)
        {
            memset(sx,0,sizeof(sx));
            memset(sy,0,sizeof(sy));
            if(path(u)) break;
            int dmin=INF;
            for(i=0;i<n;i++)
                if(sx[i])
                    for(j=0;j<n;j++)
                        if(!sy[j])
                            dmin=min(lx[i]+ly[j]-map[i][j],dmin);
                        for(i=0;i<n;i++)
                        {
                            if(sx[i])
                                lx[i]-=dmin;
                            if(sy[i])
                                ly[i]+=dmin;
                        }
        }
        int sum=0;
        for(j=0;j<n;j++)
            sum+=map[match[j]][j];
        if(!truth)
        {
            sum=-sum;
            for(i=0;i<n;i++)
                for(j=0;j<n;j++)
                    map[i][j]=-map[i][j];
        }
        return sum;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(str,0,sizeof(str));
        for(int i=0;i<n;i++)
            scanf("%s",&str[i]);
        for(int i=0;i<n;i++)  //建图
        {
            for(int j=0;j<n;j++)
            {
                if(i==j)
                {
                    map[i][j]=0;
                    continue;
                }
                int temp=0;
                int len1=strlen(str[i]),len2=strlen(str[j]);
                int len=min(len1,len2);
                for(int k=0;k<len;k++)
                {
                    if(str[i][k]==str[j][len2-k-1])
                    {
                        temp++;
                    }
                    else break;   //这里忘记break了
                }
                map[i][j]=temp;  //map[i][j]!=map[j][i],之前还以为他们是相等的……
            }
        }
        int ans=KM(1);
        printf("%d\n",ans);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值