CODE[VS]1027 姓名与ID

题目:http://codevs.cn/problem/1027/
思路:先使用匈牙利算法求解一个最长匹配解。在修改第一次求解的匹配关系,检测是否还存在其他解,如果有则无法确定对应关系,如果没有则表示匹配唯一。输入过程中如果发现一一对应关系,则通过递归来修整名字与ID的对应表。
题解:

/* 1027 姓名与ID */
#include <stdio.h>
#include <string.h>

#define MAXN 21
#define MAXID 25

int name_id[MAXN][MAXN];    /* 名字-ID对应表 */
int find_id[MAXN];          /* 已匹配ID表 */
int n;                      /* 所有人数 */
char id[MAXN][MAXID];       /* 所有ID */
char name[MAXN][MAXID];     /* 所有名字 */
int ni[MAXN];               /* 名字索引 */
int count;                  /* 名字计数 */
int in_room[MAXN];          /* 在房间人数表 */
int done[MAXN];             /* ID已存在唯一值标记 */
int state[MAXN];            /* 搜索状态标记 */
int result[MAXN];           /* 第一次匹配结果存储 */
int result1[MAXN];          /* 可能存在其他匹配结果存储 */
int ans;                    /* 匹配长度值 */

/* 匈牙利算法求解最长匹配 */
int find(int a, int flag[MAXN])
{
    int i;
    for(i = 1; i <= n; i++)
    {
        if(1 == name_id[a][i] && 0 == state[i])
        {
            state[i] = 1;
            if(0 == flag[i] || find(flag[i], flag))
            {
                flag[i] = a;
                return 1;
            }
        }

    }
    return 0;
}

/* 检测编号为i的ID与名字是否存在匹配 */
int check(int i)
{
    int p, tp;      /* 名字索引与匹配名字记录 */
    int c = 0;      /* 存在可能名字计数 */
    for(p = 1; p <= n; p++)
    {
        if(1 == name_id[p][i])
        {
            c = c + 1;
            tp = p;
        }
    }
    /* 存在唯一匹配,返回匹配名字编号,否则返回0 */
    if(1 == c)
    {
        return tp;
    }
    return 0;
}
/* 删除已匹配名字,整理名字-ID对应表 */
void prune()
{
    int i, p;
    for(i = 1; i <= n; i++)
    {
        /* 从未匹配ID表中,删除已匹配的名字 */
        if(0 == done[i])
        {
            for(p = 1; p <= n; p++)
            {
                if(0 < find_id[p] && 1 == name_id[p][i])
                {
                    name_id[p][i] = 0;
                }
            }
            /* 检测编号为i的ID是否已匹配成功 */
            if(0 < (done[i] = check(i)))
            {
                find_id[done[i]] = i;
                prune();
            }
        }

    }
}
/* 更新ID-名字链接表 */
void update(int i)
{

    int p;
    /* 从名字-ID对应表中,删除不在房间的名字 */
    for(p = 1; p <= n; p++)
    {
        /* 人不在房间且与ID存在对应关系 */
        if(0 == in_room[p] && 1 == name_id[p][i])
        {
            name_id[p][i] = 0;
        }
    }
    /* 检测编号为i的ID是否已匹配成功 */
    if(0 < (done[i] = check(i)))
    {
        find_id[done[i]] = i;
        prune();
    }
}
/* 获取ID的索引值 */
int id_num(char str[MAXN])
{
    int i;
    for(i = 1; i <= n; i++)
    {
        if(0 == strcmp(id[i], str))
        {
            return i;
        }
    }
    return 0;
}

/* 添加新名字,已存在则返回名字编号 */
int name_num(char str[MAXID])
{
    int i;
    for(i = 0; i < count; i++)
    {
        if(0 == strcmp(str, name[i + 1]))
        {
            break;
        }
    }
    /* 到达搜索边界,添加新名字 */
    if(i == count)
    {
        strcpy(name[i + 1], str);
        count++;
    }
    return i + 1;
}
/* 排序名字 */
void sort()
{
    int i, j , t;
    for(i = 1; i <= n; i++)
    {
        for(j = i + 1; j <= n; j++)
        {
            if(strcmp(name[ni[i]], name[ni[j]]) > 0)
            {
                t = ni[i];
                ni[i] = ni[j];
                ni[j] = t;
            }
        }
    }
}
/* 主函数入口 */
int main()
{
    int i, j , p;           /* 索引值 */
    int tmp_id;             /* 临时ID编号,用于第二次算法搜索 */
    char act, str[MAXID];   /* 动作与输入字符串暂存 */
    /* 打开数据文件 */
    FILE *fp;
    if(NULL == (fp = fopen("data.txt", "r")))
    {
        return 1;
    }
    /***************/
    /* 获取所有ID数 */
    fscanf(fp, "%d", &n);
    /* 获取所有ID并初始化ID链表 */
    for(i = 1; i <= n; i++)
    {
        fscanf(fp, "%s\n", id[i]);
        /* 初始化ID与名字对应表 */
        for(p = 1; p <= n; p++)
        {
            name_id[p][i] = 1;
        }
        /* 初始化房间 */
        in_room[i] = 0;
    }
    /* 获取人员动作 */
    count = 0;
    fscanf(fp, "%c", &act);
    while('Q' != act)
    {
        /* 读取名字 */
        fscanf(fp, "%s\n", str);
        /* 处理动作 */
        if('E' == act)
        {
            ni[name_num(str)] = name_num(str);
            in_room[ni[name_num(str)]] = 1;
        }
        else if ('L' == act)
        {
            in_room[ni[name_num(str)]] = 0;
        }
        else if('M' == act)
        {
            update(id_num(str));
        }

        /* 读取下一条数据 */
        fscanf(fp, "%c", &act);
    }
    /* 测试 - 打印所有名字 */
    /*
    for(i = 1; i <= n; i++)
    {
        printf("%d: %s \n", i, name[ni[i]]);
    }
    sort1();
    printf("Sort: \n");
    for(i = 1; i <= n; i++)
    {
        printf("%d: %s \n", i, name[ni[i]]);
    }
    */
    /**********************/
    /* 测试-打印最终ID对应表 */
    /*
    for(p = 1; p <= n; p++)
    {
        printf("%s : ", name[p]);
        for(i = 1; i <= n; i++)
        {
            if(1 == name_id[p][i])
            {
                printf("%s\t", id[i]);
            }
        }
        printf("\n-----------------\n");
    }
    */
    /**************************************/
    /* 做一次匈牙利算法,求一次可能匹配 */
    for(i = 1; i <= n; i++)
    {
        result[i] = 0;
    }
    ans = 0;
    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= n; j++)
        {
            state[j] = 0;
        }
        if(1 == find(i, result))
        {
            ans++;
        }
    }
    /* 测试 - 打印匹配关系 */
    /*
    printf("Ans = %d\n", ans);
    for(p = 1; p <= n; p++)
    {
        printf("%-8s -> %-8s\n", name[result[p]], id[p]);
    }
    printf("---------------\n");
    */
    /*************************************/
    for(p = 1; p <= n; p++)
    {
        if(find_id[p] > 0)
        {
            continue;
        }
        /* 初始化匹配关系 */
        for(i = 1; i <= n; i++)
        {
            result1[i] = 0;
        }
        /* 找寻第一次匹配时,与名字i对应的ID编号tmp_id */
        for(i = 1; i <= n; i++)
        {
            if(result[i] == p)
            {
                tmp_id = i;
                break;
            }
        }
        /* 修改名字与ID之间的对应关系 */
        name_id[p][tmp_id] = 0;
        ans = 0;
        /* 重新进行一次算法求解匹配 */
        for(i = 1; i <= n; i++)
        {
            for(j = 1; j <= n; j++)
            {
                state[j] = 0;
            }
            if(1 == find(i, result1))
            {
                ans++;
            }
        }
        /* 如果不能完全匹配,则表示是唯一解 */
        if(ans < n)
        {
            find_id[p] = tmp_id;
        }
        /* 测试 - 打印匹配关系 */
        /*
        printf("Ans = %d\n", ans);
        for(p = 1; p <= n; p++)
        {
            printf("%-8s -> %-8s\n", name[result1[p]], id[p]);
        }
        printf("---------------\n");
        */
        /*************************************/
        /* 恢复对应关系 */
        name_id[p][tmp_id] = 1;
    }


    /* 排序名字 */
    sort();
    /* 打印结果值 */
    for(i = 1; i <= n; i++)
    {
        if(0 != find_id[ni[i]])
        {
            printf("%s:%s\n", name[ni[i]], id[find_id[ni[i]]]);
        }
        else
        {
            printf("%s:???\n", name[ni[i]]);
        }
    }
    /*****************/
    /* 关闭文件 */
    fclose(fp);
    /************/
    return 0;
}

猜你喜欢

转载自blog.csdn.net/QQ604666459/article/details/78292487