P1285 队员分组(二分图&背包)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1285 队员分组(二分图&背包)相关的知识,希望对你有一定的参考价值。

P1285 队员分组(二分图&背包)

建边改为不认识的两人连边。

然后会形成若干个连通块。

对每个连通块进行二分图染色。

若有连通块不能完全染色肯定无解。

否则相当于每个连通块有两种选择方式:选黑点到第一组,否则选白点到第2组。预处理每个连通块的黑点和白点。

显然是个判断性背包问题。

d p [ i ] [ j ] dp[i][j] dp[i][j]对于前 i i i个连通块第一组个数为 j j j是否可行,为了输出方案还需要维护个 o p [ i ] [ j ] op[i][j] op[i][j]记录第 i i i个连通块是选择黑点还是白点。

时间复杂度: O ( C n ) , C O(Cn),C O(Cn),C是连通块个数。

// Problem: P1285 队员分组
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1285
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-08-27 16:07:42
// --------by Herio--------

#include <cstdio>
#include <cctype>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 128;
//if have char input #define should cancel
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline T& read(T& r) {
    r = 0; bool w = 0; char ch = getchar();
    while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
    return r = w ? -r : r;
}
vector<int> G[maxn],vec[maxn][2],ans[2];
inline void addedge(int from,int to){G[from].push_back(to);}
int n,tmp[maxn][maxn],f[maxn][maxn],opt[maxn][maxn],vis[maxn],col[maxn],vec_tot;
inline bool bfs(int s){
	queue<int> Q;Q.push(s);vis[s] = 1;
	vec_tot++;
	while(!Q.empty()){
		int u = Q.front();Q.pop();
		vec[vec_tot][col[u]].push_back(u);
		for(int v : G[u])
			if(!vis[v])col[v] = col[u] ^ 1,vis[v] = 1,Q.push(v);
			else if(col[v] == col[u])return false;
	}
	return true;
}
inline void solve(){
	read(n);
	for(int u = 1,v;u <= n;u++){
		while(1){
			read(v);if(!v) break;
			tmp[u][v] = 1;
		}
	}
	for(int u = 1;u <= n;u++)
		for(int v = u + 1;v <= n;v++)
			if(!(tmp[u][v] && tmp[v][u]))addedge(u,v),addedge(v,u);
	for(int i = 1;i <= n;i++)
		if(!vis[i] && !bfs(i)){
			puts("No solution");
			return;
		}
	f[0][0] = 1;
	for(int i = 1;i <= vec_tot;i++)
		for(int j = 0;j <= n;j++){
			if(j >= vec[i][0].size() && f[i - 1][j - vec[i][0].size()])f[i][j] = 1,opt[i][j] = 0;
			if(j >= vec[i][1].size() && f[i - 1][j - vec[i][1].size()])f[i][j] = 1,opt[i][j] = 1;
		}
	int now;
	for(int i = n >> 1;i >= 0;i--)
		if(f[vec_tot][i]){now = i;break;}
	for(int i = vec_tot;i >= 1;i--){
		for(auto x : vec[i][opt[i][now]])ans[0].push_back(x);
		for(auto x : vec[i][opt[i][now] ^ 1])ans[1].push_back(x);
		now -= vec[i][opt[i][now]].size();
	}
	sort(ans[0].begin(),ans[0].end());
	sort(ans[1].begin(),ans[1].end());
	printf("%d ",(int)ans[0].size());
	for(auto x : ans[0])printf("%d ",x);
	putchar('\\n');
	printf("%d ",(int)ans[1].size());
	for(auto x : ans[1])printf("%d ",x);
	putchar('\\n');
}
int main(){
	solve();
}

以上是关于P1285 队员分组(二分图&背包)的主要内容,如果未能解决你的问题,请参考以下文章

二分图匹配入门专题1I - Hiding Gold light oj 1152二分图匹配-------------------我是终于不那么水的水题分割线------------------(代码片

CF1354E Graph Coloring(构造二分图+背包)

CF-1354 E. Graph Coloring(二分图,背包,背包方案输出)

HDU-1561 The more, The Better (树形DP+分组背包)

Inviting Friends(hdu3244 &amp;&amp; zoj3187)完全背包+二分

背包(01,完全,多重,分组)