Luogu2715 小Z的游戏分队

题目描述

小Z受不了寂寞,准备举办一次DOTA比赛,为了能让ACM班全部都参加比赛,他还特制了一张DOTA地图能够支持任意多人打任意多人。

现在问题来了,怎么把这么多人分成两队?小Z的想法是,每个人报上自己愿意同队的同学,接着小Z会按如下要求将所有人分为两队:

对任意同学甲,和同学甲同队的人,必须都是同学甲愿意同队的同学。

小Z希望两队的人数差尽量小,如果这种分组不存在,那么输出No solution。

输入输出格式

输入格式:

 

第1行为N,表示一共有多少个学生。

之后2~N+1行,每行表示这个学生信任的同学的名单,以0结束。

 

输出格式:

 

1行,如果解存在,输出两队的人数,将人数比较小的那队放在前面;如果解不存在,输出No solution。

 

输入输出样例

输入样例#1:
5
3 4 5 0
1 3 5 0
2 1 4 5 0
2 3 5 0
1 2 3 4 0
输出样例#1:
No solution
输入样例#2:
5
2 3 5 0
1 4 5 3 0
1 2 5 0
1 2 3 0
4 3 2 1 0
输出样例#2:
2 3

说明

【数据规模】

对于 30% 的数据,N<=10;

对于 100% 的数据,N<=2000。

 

poj1112的超级弱化版。。。

构造反图(既如果两个人不能在一个组就连一条边),如果构造出的图不是二分图则无解,因为此时会存在某个人在两个组的时候都会有不能在一个组的人。

然后对于每一个编号(dfs的时候对于在同一条内部链的人的编号)的人可以看作一左一右两个value,每次的选择就相当于把左右的value互换,然后这就是一个背包dp了。

注意是No solution而不是No Solution

// 动态规划 判定性dp 背包dp 二分图染色

%:pragma GCC optimize(2)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>

using namespace std;

const int N = 2010;

int n, color[N], like[N][N], val[N][3], cnt;

bool f[N][N * 8];

vector<int> G[N];

void dfs(int u, int c, int dfn) {
    color[u] = c;
    ++ val[dfn][c];
    for(int i = 0 ; i < G[u].size() ; ++ i) {
        int v = G[u][i];
        if(!color[v]) {
            dfs(v, 3 - c, dfn);
        } else if(color[u] == color[v]) {
            puts("No solution");
            exit(0);
        }
    }
}

int main() {
    scanf("%d", &n);
    for(int i = 1, x ; i <= n ; ++ i) {
        while(scanf("%d", &x), x) {
            like[i][x] = 1;
        }
    }
    for(int i = 1 ; i <= n ; ++ i) {
        for(int j = 1 ; j < i ; ++ j) {
            if(!(like[i][j] && like[j][i])) {
                G[i].push_back(j);
                G[j].push_back(i);
            }
        }
    }
    for(int i = 1 ; i <= n ; ++ i) {
        if(!color[i]) {
            dfs(i, 1, ++ cnt);
        }
    }
    memset(f, 0, sizeof(f));
    #define dp(i, j) f[i][j + 4000]
    dp(0, 0) = 1;
    for(int i = 1 ; i <= cnt ; ++ i) {
        for(int j = -2000 ; j <= 2000 ; ++ j) {
            dp(i, j) |= dp(i - 1, j - val[i][1] + val[i][2]) | dp(i - 1, j - val[i][2] + val[i][1]);
        }
    }
    for(int i = 0 ; i <= 2000 ; ++ i) {
        if(dp(cnt, i)) {
            int x = (n + i) / 2, y = n - x;
            if(x > y) swap(x, y);
            printf("%d %d\n", x, y);
            return 0;
        } else if(dp(cnt, -i)) {
            int x = (n - i) / 2, y = n - x;
            if(x > y) swap(x, y);
            printf("%d %d\n", x, y);
            return 0;
        }
    }
    puts("No solution");
}

  

posted @ 2017-09-28 17:17  KingSann  阅读(226)  评论(0编辑  收藏  举报