uva1627 Team them up!

注意这题要求互相认识
不认识的人之间连一条线
一个人在组1,那么不认识(互相认识)的人就在组0;同时这些人不认识的人就在组1.每个联通分量都可以独立推导,遇到矛盾则无解
一个联通分量有一个核心,其他的点是分支
我感觉紫书写的样例又是有点问题,应该是4在0,那么135在1,反正则反;而不是1在0,345在1
然后一个联通分量的核心在一组,分支就在另一组;
设0组比1组多d,就对应d加一个或者减一个值
相当于背包

矛盾状况就是任意个联通分量不能二分染色

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn = 100 + 5;

int n, G[maxn][maxn], color[maxn], diff[maxn], cc;
vector<int> team[maxn][2]; // team[cc][c] is the list of people in connected-component cc, color c

// returns false if not bipartite graph
bool dfs(int u, int c) {
  color[u] = c;
  team[cc][c-1].push_back(u);
  for(int v = 0; v < n; v++) {
    if(u != v && !(G[u][v] && G[v][u])) { // u and v 不互相认识
      if(color[v] > 0 && color[v] == color[u]) return false;
      if(!color[v] && !dfs(v, 3-c)) return false;
    }
  }
  return true;
}

bool build_graph() {
  memset(color, 0, sizeof(color));
  cc = 0; // current connected-component
  for(int i = 0; i < n; i++)
    if(!color[i]) {
      team[cc][0].clear();  //存染成1的
      team[cc][1].clear();  //染成2的
      if(!dfs(i, 1))
        return false;
      diff[cc] = team[cc][0].size() - team[cc][1].size();
      cc++;
    }

  return true;
}

// d[i][j+n] = 1 iff we can arrange first i cc so that team 1 has j more people than team 2.
int d[maxn][maxn*2], teamno[maxn];

void print(int ans) {
  vector<int> team1, team2;
  for(int i = cc-1; i >= 0; i--) {
    int t;
    if(d[i][ans-diff[i]+n]) {
            t = 0;
            ans -= diff[i];
    }
    else {
    t = 1;
    ans += diff[i];
    }
    for(int j = 0; j < team[i][t].size(); j++)
      team1.push_back(team[i][t][j]);
    for(int j = 0; j < team[i][1^t].size(); j++)
      team2.push_back(team[i][1^t][j]);
  }


  printf("%d", team1.size());
  for(int i = 0; i < team1.size(); i++)
    printf(" %d", team1[i]+1);
  printf("\n");
  printf("%d", team2.size());
  for(int i = 0; i < team2.size(); i++)
    printf(" %d", team2[i]+1);
  printf("\n");
}

void dp() {
  memset(d, 0, sizeof(d));
  d[0][0+n] = 1;
  for(int i = 0; i < cc; i++)
    for(int j = -n; j <= n; j++) if(d[i][j+n]) {
      d[i+1][j+diff[i]+n] = 1;
      d[i+1][j-diff[i]+n] = 1;
    }
  for(int ans = 0; ans <= n; ans++) {              //差的绝对值尽量小即可
    if(d[cc][ans+n]) { print(ans); return; }
    if(d[cc][-ans+n]) { print(-ans); return; }
  }
}

int main() {
  int T;
  cin >> T;
  while(T--) {
    cin >> n;
    memset(G, 0, sizeof(G));
    for(int u = 0; u < n; u++) {
      int v;
      while(cin >> v && v) G[u][v-1] = 1;   //认识
    }

    if(n == 1 || !build_graph())
        cout << "No solution\n";
    else
        dp();
        cout << "\n";
  }
  return 0;
}

 

posted @ 2018-10-16 21:19  Erio  阅读(246)  评论(0编辑  收藏  举报