uva 1627 Team them up! 二分图 + 连通分量 + 背包

来源:互联网 发布:ubuntu无法联网 编辑:程序博客网 时间:2024/06/06 05:26
//uva 1627 Team them up! 二分图 + 连通分量 + 背包////解题思路:////同组之内每个人相互认识,如果a和b不相互认识,则//a和b只能分在两个不同的组.所以以不相互认识作为边//建图,对于每个联通块判断是否是二分图.如果不是,没有//方案,如果有,那么进行背包.//d[i][j]表示前i个连通块第一个队伍人数比第二个//队伍的人数多j个人是否合法.//推出if (d[i][j]) { d[i+1][j+diff[i]] = 1//   d[i+1][j-diff[i]] = 1}//因为有负数所以加上一个偏移量就可以了.n足矣.////初始状态下d[0][0] = 1.现在第二维加上n就ok了//然后逆推打印.////还是很巧妙的,继续加油哟~~~FIGHTING!!!#include <cstdio>#include <algorithm>#include <cstring>#include <iostream>#include <vector>#define cls(x,a) memset(x,a,sizeof(x))using namespace std;const int MAXN = 108;int n;int color[MAXN];int cc;int g[MAXN][MAXN];int d[MAXN][MAXN*2];vector<int> G[MAXN];vector<int> term[MAXN][2];bool vis[MAXN];int diff[MAXN];void input(){scanf("%d",&n);cls(g,0);cls(color,0);cls(vis,0);cls(d,0);diff[MAXN];for (int i = 0 ;i <= n;i ++){term[i][0].clear();term[i][1].clear();G[i].clear();}for (int i = 1;i <= n;i++){int v;while(scanf("%d",&v)!=EOF && v){g[i][v] = 1;}}if (n == 1){puts("No solution");return ;}for (int i=1;i<=n;i++){for (int j=1;j<=n;j++){if (i != j &&(!g[i][j] || !g[j][i])){G[i].push_back(j);G[j].push_back(i);}}}}void p(){for (int i = 0 ;i < cc; i++){for (int j = 0; j < 2 ; j++){for (int k = 0 ; k < term[i][j].size(); k++)printf("%d ",term[i][j][k]);puts("");}puts("");}}bool dfs(int u,int c){color[u] = c;vis[u] = 1;term[cc][c-1].push_back(u);for (int i=0;i < G[u].size();i ++){int v = G[u][i];if (v == u) continue;if (color[v] && color[u] == color[v]) return false;if (!color[v] && !dfs(v,3-c))return false;}return true;}void print(int ans){vector<int> term1,term2;int t;for (int i = cc - 1;i >= 0 ;i --){if (d[i][ans-diff[i]+n]){t = 0;ans -= diff[i];}else {t = 1;ans += diff[i];}for (int j = 0; j < term[i][t].size(); j++){term1.push_back(term[i][t][j]);}for (int j = 0;j < term[i][t^1].size(); j++)term2.push_back(term[i][t^1][j]);}printf("%d",term1.size());for (int j = 0;j < term1.size(); j++)printf(" %d",term1[j]);puts("");printf("%d",term2.size());for (int j = 0;j < term2.size(); j++)printf(" %d",term2[j]);puts("");}void DP(){d[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;}}}//p();for (int i = 0 ;i <= n;i ++){if (d[cc][i+n]){print(i);return ;}if (d[cc][-i+n]){print(-i);return ;}}}void solve(){int flag = 0;cc = 0;for (int i = 1;i <= n;i ++){if (!color[i]){if (!dfs(i,1)){flag = 1;break;}diff[cc] = term[cc][0].size() - term[cc][1].size();cc++;}}if (flag){puts("No solution");return ;}DP();}int main(){int t;//freopen("1.txt","r",stdin);scanf("%d",&t);while(t--){input();solve();puts("");}return 0;}

0 0
原创粉丝点击