社区讨论
18pts!玄关!
P1285[NEERC 2001] 队员分组参与者 3已保存回复 5
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 5 条
- 当前快照
- 1 份
- 快照标识符
- @mdrcj1oo
- 此快照首次捕获于
- 2025/07/31 20:03 7 个月前
- 此快照最后确认于
- 2025/11/04 03:24 4 个月前
CPP
/*
解题思路:
1.把没有关系的队员连线
2.用 黑-白-黑-白 的方式染色每一个联通块
3.01背包来选出那些在A组
*/
#include<bits/stdc++.h>
using namespace std;
const int N=1e2+10;
bool dp[N][N],know[N][N],book[N];
int colour[N],r[N][N],head[N][N];
int sum,ans,n,ar;
vector<int>vec[N][3];//vecc[i][j] : i联通块j组(颜色)
void dfs(int x,int fa,int c){//染色
colour[x]=c;
vec[sum][c].push_back(x);
for(int i=1;i<=n;i++){
if(!know[x][i]&&i!=x&&i!=fa){//都认识
if(!colour[i]) dfs(i,x,3-c);
else{
if(colour[i]==c){//以 黑-白-黑-白 染色,所以如果一样就输出No solution
cout<<"No solution";
exit(0);
}
}
}
}
}
void bag01(){//dp
dp[0][0]=1;
//dp[i][j] : 在前i个联通块中选,能否使A组的人数>=j
for(int i=1;i<=sum;i++){
for(int j=1;j<=n;j++){
if(j>=vec[i][0].size()&&dp[i-1][j-vec[i][0].size()])//如果上一个有方法
dp[i][j]=1,r[i][j]=1,head[i][j]=j-vec[i][0].size();
if(j>=vec[i][1].size()&&dp[i-1][j-vec[i][1].size()])//如果上一个有方法
dp[i][j]=1,r[i][j]=2,head[i][j]=j-vec[i][1].size();
}
}
for(int i=n/2;i>=1;i--){//因为要平均,所以倒着枚
if(dp[sum][i]){
ans=i;
return;
}
}
}
int main(){
ios::sync_with_stdio(false); // 关闭与 C 标准库的同步
cin.tie(nullptr); // 解除 cin 和 cout 的绑定
cout.tie(nullptr); // 可选,进一步优化输出
cin>>n;
for(int i=1;i<=n;i++){
while(cin>>ar){
if(ar==0) break;
else know[i][ar]=1;
}
}
for(int i=1;i<=n;i++){
if(!colour[i]){
sum++;
dfs(i,0,1);
}
}
bag01();
cout<<ans<<" ";
int a=sum,b=ans;
while(a&&b){
for(int i=0;i<vec[a][r[a][b]].size();i++){
book[vec[a][r[a][b]][i]]++;
}
b=head[a--][b];
}
for(int i=1;i<=n;i++)
if(book[i]) cout<<i<<" ";
cout<<endl<<n-ans<<" ";
for(int i=1;i<=n;i++)
if(!book[i]) cout<<i<<" ";
return 0;
}
回复
共 5 条回复,欢迎继续交流。
正在加载回复...