题意:
给出n个人以及认识其他人的情况,现在要把所有人分成两队,每队至少一人,求使两队人数差距最小且每队内部的人都相互认识的分队情况。
分析:
这道题让我学习到了不少,首先看到使差距最小就想到了背包,但是不会表示分队情况。看了别人的思路,这个很明显是要判断是否是二分图,让不是相互认识的两人连一条边,若不是二分图则不能分成两队。利用染色法判断二分图,则每个连通分量都包含0,1两个集合。
dp[i][j]表示i个联通分量能组成符合条件的人数为j的一队,par[i][j]记录路径
#include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <cstdio> #include <vector> #include <string> #include <cctype> #include <complex> #include <cassert> #include <utility> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; typedef pair<int,int> PII; typedef long long ll; #define lson l,m,rt<<1 #define pi acos(-1.0) #define rson m+1,r,rt<<11 #define All 1,N,1 #define N 110 #define read freopen("in.txt", "r", stdin) const ll INFll = 0x3f3f3f3f3f3f3f3fLL; const int INF= 0x7ffffff; const int mod = 1000000007; int n,tim,num; int dp[N][N],par[N][N],mapc[N][N],part[N][2]; int color[N],dfn[N],f[N],road[N][N][2]; vector<int>e[N]; int dfs(int u){ dfn[u]=++tim; road[num][++part[num][color[u]]][color[u]]=u; for(int i=0;i<e[u].size();++i){ int v=e[u][i]; if(dfn[v]==0){ color[v]=(!color[u]); if(dfs(v)==0)return 0; } else{ if(v!=u&&color[u]==color[v])return 0; } } return 1; } void hand(){ int v; for(v=n/2;v>=0;--v){ if(dp[num][v]) break; } if(v==0){printf("No solution\n");return;} memset(f,0,sizeof(f)); int tmp=v,t; for(int i=num;i>=0;--i){ t=par[i][tmp]; tmp-=part[i][t]; for(int j=1;j<=part[i][t];++j) f[road[i][j][t]]=1; } printf("%d",v); for(int i=1;i<=n;++i) if(f[i]) printf(" %d",i); printf("\n"); printf("%d",n-v); for(int i=1;i<=n;++i) if(!f[i]) printf(" %d",i); printf("\n"); } void solve(){ memset(part,0,sizeof(part)); memset(color,0,sizeof(color)); memset(dfn,0,sizeof(dfn)); memset(dp,0,sizeof(dp)); tim=num=0; int k; for(k=1;k<=n;++k){ if(!dfn[k]){ ++num; if(dfs(k)==0)break; } } if(k<=n)printf("No solution\n"); else{ dp[0][0]=1; for(int i=1;i<=num;++i) for(int j=0;j<=n/2;++j){ int tmp=j-part[i][0]; if(tmp>=0&&dp[i-1][tmp]){ dp[i][j]=1; par[i][j]=0; } tmp=j-part[i][1]; if(tmp>=0&&dp[i-1][tmp]) { dp[i][j]=1; par[i][j]=1; } } hand(); } } int main() { int ca=0; scanf("%d",&ca); while(ca--){ scanf("%d",&n); int a; memset(mapc,0,sizeof(mapc)); for(int i=1;i<=n;++i) e[i].clear(); for(int i=1;i<=n;++i){ while(~scanf("%d",&a)&&a){ mapc[i][a]=1; } } for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) if(mapc[i][j]==0||mapc[j][i]==0){ e[i].push_back(j); e[j].push_back(i); } solve(); if(ca)printf("\n"); } return 0; }
时间: 2024-11-05 12:14:00