【问题标题】:Why am I keep getting WA for this solution for UVa 10511为什么我一直为 UVa 10511 这个解决方案获得 WA
【发布时间】:2015-01-03 23:49:41
【问题描述】:

我正在尝试解决这个问题,我想我已经想出了一个正确的答案,但我不断收到法官的 WA(错误答案)回复。

http://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=1452

提炼出来的问题是,给定党和个人之间的 1 - * 关系,以及个人和俱乐部之间的 1 - * 关系。找到个人和俱乐部之间的 1 对 1 关系,使得对于与俱乐部相关的所有人,属于任何一方的人数少于俱乐部人数的一半。

例如,假设我们有

Person1 属于 Party1 和 Club1、Club2

Person2 属于 Party2 和 Club2、Club3

Person3 属于 Party3 和 Club3、Club1

有两种可能的分配。

Person1 Club1

Person2 Club2

Person3 Club3

Person1 Club2

Person2 Club3

Person3 Club1

我的想法是将此问题建模为最大流量问题,如下所示:

为简单起见,假设有两个聚会,四个人,三个俱乐部。

0 是主源

1、2是代表双方的节点

3、4、5、6是代表四个人的节点

7、8、9是代表三个俱乐部的节点。

10 是主接收器

主源以容量 = (3 + 1)/2 - 1 = 1 连接到每一方。这表示议会中最多只能有 1 人代表 1 方(否则 2 将等于或一半以上)

对于每个派对人对,有一个容量为 1 的链接。这表示每个人只有 1 个派对,并且使用了之前分配的人数中的一个席位。

对于每个人俱乐部对,有一个容量为 1 的链接。这表示每个人只能代表一个俱乐部。

最后但并非最不重要的一点是,所有俱乐部都会以容量 1 沉没。

如果上图的最大流量等于俱乐部的数量 - 则存在分配。

我可以证明这个设计是正确的:

=>

如果存在大小的最大流量,则每个俱乐部节点必须发送值为 1 的流量,这意味着每个俱乐部节点只有一个人代表它。该表示尊重政党参与的约束,因为它最多有多少人在一个政党中,由政党节点流代表。

如果有表示,则如上构造流,使流存在。流量是最大的,因为最大可能的流量受到连接到 sink 的边的约束。

所以上面的参数或者实现一定有问题。

废话不多说,这是我的源代码:

#include "stdafx.h"

// http://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=1452

// #define LOG

#include "UVa10511.h"

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <queue>

using namespace std;

int UVa10511_assign_person_number(map<string, int>& person_numbers, map<int, string>& person_namings, string person_name);
int UVa10511_assign_party_number(map<string, int>& party_numbers, map<int, string>& party_namings, string party_name);
int UVa10511_assign_club_number(map<string, int>& club_numbers, map<int, string>& club_namings, string club_name);
int UVa10511_Edmonds_Karps(vector<vector<int>>& capacities, vector<vector<int>>& adjacency_list, int src, int dst);

int UVa10511()
{
    string line;
    int number_of_test_cases;
    cin >> number_of_test_cases;
    getline(cin, line); // consume the blank link after the number of test cases    
    getline(cin, line); // consume the blank link before the first test case
    for (int test_case = 0; test_case < number_of_test_cases; test_case++)
    {
        map<string, int> person_numbers;
        map<int, string> person_namings;
        map<string, int> party_numbers;
        map<int, string> party_namings;
        map<string, int> club_numbers;
        map<int, string> club_namings;

        vector<pair<int, int>> party_members;
        vector<pair<int, int>> person_clubs;

        while(getline(cin, line) && line != "" && line != " ")
        {
            string person_name;
            string party_name;
            string club_name;
            stringstream sin(line);
            sin >> person_name >> party_name;

            int person_id = UVa10511_assign_person_number(person_numbers, person_namings, person_name);
            int party_id = UVa10511_assign_party_number(party_numbers, party_namings, party_name);
            party_members.push_back(pair<int, int>(party_id, person_id));
            while(sin >> club_name)
            {
                int club_id = UVa10511_assign_club_number(club_numbers, club_namings, club_name);
                person_clubs.push_back(pair<int, int>(person_id, club_id));
            }   
        }

        int number_of_parties = party_numbers.size();
        int number_of_persons = person_numbers.size();
        int number_of_clubs = club_numbers.size();

        int number_of_nodes =
            /* master source */ 1 +
            /* parties       */ number_of_parties +
            /* person        */ number_of_persons +
            /* clubs         */ number_of_clubs +
            /* master sink   */ 1;

        vector<vector<int>> capacities;
        vector<vector<int>> adjacency_list;

        capacities.resize(number_of_nodes);
        adjacency_list.resize(number_of_nodes);

        for (int src = 0; src < number_of_nodes; src++)
        {
            capacities[src].resize(number_of_nodes);
            for (int dst = 0; dst < number_of_nodes; dst++)
            {
                capacities[src][dst] = 0;
            }
        }

        int max_party_participants = (number_of_clubs - 1) / 2; // Floor intended, not equal or more than half

        for (int p = 0; p < number_of_parties; p++)
        {
            int party_node = p + 1;
            capacities[0][party_node] = max_party_participants;
            adjacency_list[0].push_back(party_node);
            adjacency_list[party_node].push_back(0);
        }

        int person_node_start = 1 + number_of_parties;

        for (vector<pair<int, int>>::iterator pmi = party_members.begin(); pmi != party_members.end(); pmi++)
        {
            int party_id = pmi->first;
            int person_id = pmi->second;

            int party_node = party_id + 1;
            int person_node = person_node_start + person_id;

            capacities[party_node][person_node] = 1;
            adjacency_list[party_node].push_back(person_node);
            adjacency_list[person_node].push_back(party_node);
        }

        int club_node_start = 1 + number_of_parties + number_of_persons;
        for (vector<pair<int, int>>::iterator pci = person_clubs.begin(); pci != person_clubs.end(); pci++)
        {
            int person_id = pci->first;
            int club_id = pci->second;

            int person_node = person_node_start + person_id;
            int club_node = club_node_start + club_id;

            capacities[person_node][club_node] = 1;
            adjacency_list[person_node].push_back(club_node);
            adjacency_list[club_node].push_back(person_node);
        }

        for (int c = 0; c < number_of_clubs; c++)
        {
            int club_node = club_node_start + c;
            capacities[club_node][number_of_nodes - 1] = 1;
            adjacency_list[club_node].push_back(number_of_nodes - 1);
            adjacency_list[number_of_nodes - 1].push_back(club_node);
        }

#ifdef LOG
        cout << "digraph {" << endl;
        for (int src = 0; src < number_of_nodes; src++)
        {
            for (vector<int>::iterator di = adjacency_list[src].begin(); di != adjacency_list[src].end(); di++)
            {
                int dst = *di;
                cout << src << "->" << dst << " [label=\"" << capacities[src][dst] << "\"];" << endl;
            }
        }
        cout << "}" << endl;
#endif

        int total_flow = UVa10511_Edmonds_Karps(capacities, adjacency_list, 0, number_of_nodes - 1);

        if (test_case > 0)
        {
            cout << endl;
        }

        if (total_flow == number_of_clubs)
        {

            for (vector<pair<int, int>>::iterator pci = person_clubs.begin(); pci != person_clubs.end(); pci++)
            {
                int person_id = pci->first;
                int club_id = pci->second;

                int person_node = person_node_start + person_id;
                int club_node = club_node_start + club_id;

                if (capacities[person_node][club_node] == 0)
                {
                    cout << person_namings[person_id] << " " << club_namings[club_id] << endl;
                }
            }
        }
        else
        {
            cout << "Impossible." << endl;
        }
    }

    return 0;
}

int UVa10511_assign_party_number(map<string, int>& party_numbers, map<int, string>& party_namings, string party_name)
{
    int party_number;
    map<string, int>::iterator probe = party_numbers.find(party_name);
    if (probe == party_numbers.end())
    {
        party_number = party_numbers.size();
        party_numbers.insert(pair<string, int>(party_name, party_number));
        party_namings.insert(pair<int, string>(party_number, party_name));
    }
    else
    {
        party_number = probe->second;
    }

    return party_number;
}

int UVa10511_assign_person_number(map<string, int>& person_numbers, map<int, string>& person_namings, string person_name)
{
    int person_number;
    map<string, int>::iterator probe = person_numbers.find(person_name);
    if (probe == person_numbers.end())
    {
        person_number = person_numbers.size();
        person_numbers.insert(pair<string, int>(person_name, person_number));
        person_namings.insert(pair<int, string>(person_number, person_name));
    }
    else
    {
        person_number = probe->second;
    }

    return person_number;
}

int UVa10511_assign_club_number(map<string, int>& club_numbers, map<int, string>& club_namings, string club_name)
{
    int club_number;
    map<string, int>::iterator probe = club_numbers.find(club_name);
    if (probe == club_numbers.end())
    {
        club_number = club_numbers.size();
        club_numbers.insert(pair<string, int>(club_name, club_number));
        club_namings.insert(pair<int, string>(club_number, club_name));
    }
    else
    {
        club_number = probe->second;
    }

    return club_number;
}

int UVa10511_Edmonds_Karps(vector<vector<int>>& capacities, vector<vector<int>>& adjacency_list, int src, int dst)
{
    int total_flow = 0;
    // Step 2: Edmonds Karp's
    vector<int> parents; // Allow back-tracking the path found from bfs
    int number_of_nodes = capacities.size();
    parents.resize(number_of_nodes); // avoid reallocation
    while (true)
    {
        // Step 2.1: Use BFS to find an augmenting flow
        queue<int> bfs_queue;
        for (int n = 0; n < number_of_nodes; n++)
        {
            parents[n] = -1; // indicating the node is not enqueued
        }

        parents[src] = -2; // indicating the node is enqueued but no actual parent because this is the root
        bfs_queue.push(src);
        while (bfs_queue.size() > 0)
        {
            int current = bfs_queue.front();
            bfs_queue.pop();
            for (vector<int>::iterator ni = adjacency_list[current].begin(); ni != adjacency_list[current].end(); ni++)
            {
                int neighbor = *ni;
                if (parents[neighbor] == -1 && capacities[current][neighbor] > 0)
                {
                    parents[neighbor] = current;
                    bfs_queue.push(neighbor);

                    if (neighbor == dst)
                    {
                        break;
                    }
                }
            }
            if (parents[dst] != -1)
            {
                break;
            }
        }

        if (parents[dst] == -1)
        {
            break;
        }
        else
        {
            // We have found an augmenting path, go through the path and find the max flow through this path
            int cur = dst;
            bool first = true;
            int max_flow_through_path = 0;
            while (true)
            {
                int src = parents[cur];
                if (src != -2)
                {
                    int dst = cur;
                    int available = capacities[src][dst];
#ifdef LOG
                    cout << src << "--" << available << "->" << dst << endl;
#endif
                    cur = parents[cur];
                    if (first)
                    {
                        max_flow_through_path = available;
                        first = false;
                    }
                    else
                    {
                        max_flow_through_path = min(max_flow_through_path, available);
                    }
                }
                else
                {
                    break;
                }
            }
#ifdef LOG
            cout << "flowing " << max_flow_through_path << endl << endl;
#endif
            total_flow += max_flow_through_path;
            // Flow the max flow through the augmenting path
            cur = dst;
            while (true)
            {
                int src = parents[cur];
                if (src != -2)
                {
                    capacities[src][cur] -= max_flow_through_path;
                    capacities[cur][src] += max_flow_through_path;
                    cur = parents[cur];
                }
                else
                {
                    break;
                }
            }
        }
    }

    return total_flow;
}

源代码也发布在 https://github.com/cshung/Competition/blob/master/Competition/UVa10511.cpp

相同的 Edmonds Karps 程序用于通过其他一些 UVa 问题,所以我认为应该没问题。

UVa820、UVa10480、UVa10779、UVa11506、UVa563 均被此 Edmonds Karp 程序接受 (这些代码也可以在 Git 存储库中找到)

我什至调试了 Edmond Karps 错误地选择修复它并为此测试用例增加路径的情况

1

Person1 Party1 Club1 Club2

Person2 Party2 Club3

Person3 Party3 Club1

由于我的 Edmond Karps 在邻接列表顺序中使用 BFS,所以选择的路径是

Master Source -> Party1 -> Person1 -> Club1 -> Master Sink

Master Source -> Party2 -> Person2 -> Club3 -> Master Sink

Master Source -> Party3 -> Person3 -> Club1 -> Person1 -> Club2 -> Master Sink [这使用了反向边缘并证明通过反向边缘工作]

现在我真的卡住了,真的不知道出了什么问题,感谢任何帮助。

【问题讨论】:

  • 我对这种说法感到困惑:“任何一方的人数少于俱乐部人数的一半”。这似乎意味着每个俱乐部至少需要 3 人,而这 3 人需要来自不同的政党。一个俱乐部有 1 个人,那么 100% 的人来自同一个聚会。一个俱乐部有 2 个人,有 50% 的两个派对。因此,必须有 3 人或更多人在一个俱乐部中,然后少于一半的人来自一个派对。我在这里错过了什么?
  • 当我将问题解释为“属于任何一方的人数少于俱乐部人数的一半”时,我的意思是“与俱乐部有关的人数 /b> 属于任何一方的人数少于俱乐部人数的一半”。例如 - 如果您只有 4 个人和 3 个俱乐部。像这样: Person1 Party1 Club1 Person2 Party2 Club2 Person3 Party3 Club3 Person 和 Club 之间的 1-1 关系将是 Person1 Club1 Person2 Club2 Person3 Club3 Party1, 2 和 3 都有 1/3 的参与(在与 a 相关的所有人员的集合中俱乐部)我希望这能解决问题。

标签: algorithm


【解决方案1】:

你对这个问题的想法是正确的,这是一个使用最大流算法的典型问题。

我一遍又一遍地阅读你的代码,我找不到任何错误。然后我改变了你处理输入的方式,然后我得到了 UVA 的接受。

只需更改代码

// you code 
cin >> number_of_test_cases;
getline(cin, line); // consume the blank link before the first test case
getline(cin, line); // consume the blank link before the first test case

//line 43
while(getline(cin, line) && line != "" && line != " ")

// change to
scanf("%d\n", &number_of_test_cases);

//line 43
// while(getline(cin, line) && line.length() > 0)

更改代码后,我得到了 uva 的接受。

希望得到您的接受回复。

【讨论】:

    猜你喜欢
    • 2021-05-20
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多