1 条题解

  • 0
    @ 2025-4-19 21:16:20

    算法标签:

    动态规划 背包 搜索 DFS

    题解:

    1、只有互相认识的人才能放在同一个组,也就是说前面3中情况都不能放在一个组;

    2、在满足前面3中情况的两两之间连线,建立无向图G(可能不是连通图,存在连通分支);

    3、在G中连线的2个人肯定是不能放在同一个分组里面,于是DFS染色,判断G是否是二分图。如果图G不是二分图,那么肯定无解;

    如果G是二分图,计算每个连通分支中分成属于x[i],y[i]2个组的人数(i表示连通分支);

    4、对X,Y 2组人员DP(经典的背包问题);可以对2个组之间的差值DP范围是(-100~+100),也可以对2个组的人数DP;我选择的是后一种办法。

    dp[i]j表示第1组为i个人,第2组为j个人这个状态;dp[i][j]=1表示存在。初始dp[0][0] = 1;然后对每个连通分支DP,转移方程:

    if dp[i][j]=1

    dp[i+x[k]][j+y[k]] = 1

    dp[i+y[k]][j+x[k]] = 1

    最后取个差值最小的;

    #include <iostream>
    #include <cstring>
    #include<cmath>
    #define inf 1000000
    using namespace std;
    const int MAXN = 101;
    int map[MAXN][MAXN];
    int id[2][MAXN];
    int color[MAXN];
    int dp[MAXN][MAXN];
    int tmp[MAXN][MAXN];
    struct  
    {
        int c1, c2;
        int i, j;
    } pre[MAXN][MAXN];
    int N, t;
    
    bool DFS(int CurV, int c)
    {
        color[CurV] = c;
        id[c % 2][t]++;
        bool ans = true;
        for (int i = 1; i <= N; i++)
        {
            if (map[CurV][i] == 1)
            {
                if (color[i] == -1)
                {
                    ans = DFS(i, (c % 2 == 0)? (c + 1) : (c - 1));
                    if (ans == false)
                        return false;
                }
                else if (color[i] == color[CurV])
                    return false;
            }
        }
        return true;
    }
    
    int main()
    {
        //freopen("test.txt", "r", stdin);
        cin >> N;
        memset(map, 0, sizeof(map));
        memset(id, 0, sizeof(id));
        memset(color, 0xff, sizeof(color));
        memset(tmp, 0, sizeof(tmp));
        memset(dp, 0, sizeof(dp));
    
        for (int i = 1; i <= N; i++)
        {
            int j;
            while (cin >> j && j != 0)
                tmp[i][j] = 1;
        }
        for (int i = 1; i <= N; i++)
        {
            for (int j = i + 1; j <= N; j++)
            {
                if (!(tmp[i][j] == 1 && tmp[j][i] == 1))
                    map[i][j] = map[j][i] = 1;
            }
        }
        bool ans;
        int c = 0;
        t = 0;
        for (int i = 1; i <= N; i++)
        {
            if (color[i] == -1)
            {
                ans = DFS(i, c);
                c += 2;
                t++;
                if (ans == false)
                    break;
            }
        }
        if (ans == false)
            cout << "No solution" << endl;
        else
        {
            int n = 0;
            dp[0][0] = 1;
            for (int k = 0; k < t; k++)
            {
                for (int i = 0; i <= n; i++)
                {
                    int j = n - i;
                    if (dp[i + id[0][k]][j + id[1][k]] == 0 && dp[i][j] == 1)
                    {
                        pre[i + id[0][k]][j + id[1][k]].c1 = k * 2;
                        pre[i + id[0][k]][j + id[1][k]].c2 = k * 2 + 1;
                        pre[i + id[0][k]][j + id[1][k]].i = i;
                        pre[i + id[0][k]][j + id[1][k]].j = j;
                        dp[i + id[0][k]][j + id[1][k]] = 1;
                    }
                    if (dp[i + id[1][k]][j + id[0][k]] == 0 && dp[i][j] == 1)
                    {
                        pre[i + id[1][k]][j + id[0][k]].c1 = k * 2 + 1; // 记录颜色
                        pre[i + id[1][k]][j + id[0][k]].c2 = k * 2; // 记录颜色
                        pre[i + id[1][k]][j + id[0][k]].i = i;
                        pre[i + id[1][k]][j + id[0][k]].j = j;
                        dp[i + id[1][k]][j + id[0][k]] = 1;
                    }
                }
                n += id[0][k] + id[1][k];
            }
            int res = inf;
            int a, b;
            for (int i = 1; i <= N; i++)
            {
                int j = N - i;
                if (dp[i][j] == 1 && res > abs(i - j))
                {
                    a = i;
                    b = j;
                    res = abs(i - j);
                }
            }
            cout << a;
            for (int i = a, j = b; !(i == 0 && j == 0);)
            {
                int c = pre[i][j].c1;
                for (int k = 1; k <= N; k++)
                {
                    if (color[k] == c)
                        cout << " " << k;
                }
                int _i = i;
                i = pre[i][j].i;
                j = pre[_i][j].j;
            }
            cout << endl;
            cout << b;
            for (int i = a, j = b; !(i == 0 && j == 0);)
            {
                int c = pre[i][j].c2;
                for (int k = 1; k <= N; k++)
                {
                    if (color[k] == c)
                        cout << " " << k;
                }
                int _i = i;
                i = pre[i][j].i;
                j = pre[_i][j].j;
            }
            cout << endl;
        }
        return 0;
    }    
    
    • 1

    信息

    ID
    113
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者