UVA 1627 Team them up!

https://cn.vjudge.net/problem/UVA-1627

题目

有n(n≤100)个人,把他们分成非空的两组,使得每个人都被分到一组,且同组中的人相互认识。要求两组的成员人数尽量接近。多解时输出任意方案,无解时输出No Solution。

例如,1认识2, 3, 5;2认识1, 3, 4, 5;3认识1, 2, 5,4认识1, 2, 3,5认识1, 2, 3, 4(注意4认识1但1不认识4),则可以分两组:{1,3,5}和{2,4}。

题解

不是互相认识的连边,然后保证一条边的两个人分到两个不同的组

一个连通分量的人可以存起来……那么类似于poj1417最后的dp部分

设$dp[i][j]$为前i个连通块,两组人数差为j时是否存在

因为j可能为负数,不方便迭代,于是改为设$dp[i][100+j]$

易证若差为j时存在,那么差为-j时也存在,于是最后只用枚举$dp[conn][100..100+n]$是否存在,然后按照dp相反的方向输出解(因为要看每一次的决策是什么)

AC代码

#include<bits/stdc++.h>
using namespace std;

#define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define PER(r,x,y) for(register int r=(x); r>(y); r--)
#define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
#define PERE(r,x,y) for(register int r=(x); r>=(y); r--)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...) (void)0
#endif
int n;
int G[107][107];
bool tmp[107];
int v[107],conn=0,r[107];
int vis[107];
bool failed;
int dp[107][207];
int cho[107];
inline int signx(int x, int k) {
	int ans=1;
	int t=x+1; if(t>n) t=1;
	vis[x]=k;
	do {
		if(G[x][t]) {
			if(!vis[t])
				ans-=signx(t,-k);
			else if(vis[t]!=-k) {
				failed = true;
				return 0;
			}
		}
		if(failed) return 0;
		t++; if(t>n) t=1;
	} while(t!=x);
	return ans;
}
int ansarr[107][2], ansn[2]={0,0};
inline void anx(int x, int i) {
	ansarr[ansn[i]++][i]=x;
	int t=x+1; if(t>n) t=1;
	vis[x]=-2;
	do {
		if(G[x][t] && vis[t]!=-2) {
			anx(t, !i);
		}
		t++; if(t>n) t=1;
	} while(t!=x);
}
int main() {
	#ifdef sahdsg
	freopen("in.txt","r",stdin);
	#endif
	int t; scanf("%d", &t);
	while(0<t--) {
		scanf("%d", &n); memset(G,0,sizeof G); memset(vis,0,sizeof vis); conn=0;
		REPE(i,1,n) {
			int v;
			memset(tmp,0,sizeof tmp);
			tmp[i]=1;
			while(1) {
				scanf("%d", &v);
				if(v==0) break;
				tmp[v]=1;
			}
			REPE(j,1,n) if(tmp[j]==0) G[i][j]=G[j][i]=1;
		}
		failed = false;
		int a=0;
		REPE(i,1,n) {
			if(!vis[i]) {r[++conn]=i; v[conn]=signx(i,1);}
			if(failed) {
				goto _wa;
			}
		}
		#define in(x) ((x)<=200 && (x)>=0)
		memset(dp,0,sizeof dp);
		dp[0][100]=1;
		REPE(i,1,conn) {
			REPE(j,100-n,100+n) {
				if(in(j-v[i]) && dp[i-1][j-v[i]]) dp[i][j]=1;
				else if(in(j+v[i]) && dp[i-1][j+v[i]]) dp[i][j]=1;
			}
		}
		memset(ansn,0,sizeof ansn);
		for(; a<=n; a++) {
			if(dp[conn][100+a]) {
				break;
			}
		}
		PERE(i,conn,1) {
			if(in(100+a-v[i]) && dp[i-1][100+a-v[i]]) a-=v[i],anx(r[i],0);
			else if(in(100+a+v[i]) && dp[i-1][100+a+v[i]]) a+=v[i],anx(r[i],1);
		}
		#undef in
		REPE(j,0,1) {
			printf("%d", ansn[j]);
			REP(i,0,ansn[j]) {
				printf(" %d", ansarr[i][j]);
			}
			putchar('
');
		}
		if(t) putchar('
'); continue;
		_wa:
			puts("No solution"); if(t) putchar('
'); continue;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/sahdsg/p/10601609.html