您的位置:首页 > 其它

jzoj3782 [NOIP2014模拟8.17] 组队

2018-02-03 19:31 330 查看

Description

你的任务是将一群人分到两个队伍中,使得:

1、每个人都属于一个队伍。

2、每个队伍至少有一个人。

3、每个队伍的任意一个人都认识其他人。

4、两支队伍的人数尽可能接近。

这个任务可能有多组解,你可以输出任意一种。

注意:认识是单向的且没有传递性。

对于分值为 30%的数据,N <= 15

对于剩余分值为 70%的数据,N <= 100

[评分标准]

该题采用捆绑测试点评测的方式,即一组测试点包括许多测试点,对于每组测试点,你的必须通过该组测试点下的所有单个测试点才能得到全部分数,任意测试点错误都会导致该组测试点不得分。

该测试方式只为了提高测试准确度,并不会对选手的时间限制等造成影响。

即选手在编写程序时不需要考虑任何额外的操作。

Solution

考试的时候盯着100的n看光想最小割了

可以转化为经典的2-sat模型,若两人无论如何都不能分在一组就连一条无向边。对于每个连通块单独讨论,如果不能黑白染色就无解。dp[k][i][j]表示能否实现前k个连通块一组分了i人另一组分了j人,转移的时候记录方案即可

捆绑数据真恶心,只有四种得分

Code

#include <stdio.h>
#include <string.h>
#include <stack>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)

const int N=205;
const int E=50005;

struct edge{int x,y,next;}e[E];
bool rc

,inStack
,vis
;
int dfn
,low
,scc
;
int col
,a
,b
;
int f

,rec

;
int ls
,edCnt;
std:: stack<int> stack;
bool flag;

void addEdge(int x,int y) {
e[++edCnt]=(edge){x,y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge){y,x,ls[y]}; ls[y]=edCnt;
// printf("%d %d\n", x,y);
}

void color(int now,int id) {
if (!flag) return ;
vis[now]=1; col[now]=id; scc[now]=scc[0];
for (int i=ls[now];i;i=e[i].next) {
if (!vis[e[i].y]) color(e[i].y,id^1);
else if (col[e[i].y]==id) {
flag=false;
return ;
}
}
}

void build(int n) {
rep(i,1,n) {
rep(j,i+1,n) {
if (!rc[i][j]||!rc[j][i]) {
addEdge(i,j);
}
}
}
}

void dp(int n) {
f[0][0][0]=1;
rep(k,1,scc[0]) {
drp(i,n,0) {
drp(j,n,0) {
if (i==0&&j==0) continue;
if (i>=a[k]&&j>=b[k]&&f[k-1][i-a[k]][j-b[k]]) {
f[k][i][j]=1;
rec[k][i][j]=1;
}
if (i>=b[k]&&j>=a[k]&&f[k-1][i-b[k]][j-a[k]]) {
f[k][i][j]=1;
rec[k][i][j]=2;
}
}
}
}
}

int main(void) {
freopen("data.in","r",stdin);
int n; scanf("%d",&n);
rep(i,1,n) {
int x; scanf("%d",&x);
while (x) {
rc[i][x]=1;
scanf("%d",&x);
}
}
build(n);
flag=true;
rep(i,1,n) {
if (!vis[i]) {
scc[0]++;
color(i,1);
}
if (!flag) {
puts("-1");
return 0;
}
}
rep(i,1,n) {
a[scc[i]]+=(col[i]==1);
b[scc[i]]+=(col[i]==0);
}
dp(n);
// puts("");
// rep(i,1,scc[0]) printf("%d %d\n", a[i],b[i]);
// puts("");
// printf("%d %d\n", rec[2][2][3], rec[1][1][3]);
drp(i,n/2,1) {
int ti=i,tj=n-i;
if (f[scc[0]][ti][tj]) {
printf("%d ", ti);
drp(k,scc[0],1) {
rep(j,1,n) {
if (scc[j]==k&&col[j]+1!=rec[k][ti][tj]) printf("%d ", j);
}
if (rec[k][ti][tj]==1) {
ti-=a[k];
tj-=b[k];
} else if (rec[k][ti][tj]==2) {
ti-=b[k];
tj-=a[k];
}
}
ti=i,tj=n-i;
printf("\n%d ", tj);
drp(k,scc[0],1) {
rep(j,1,n) {
if (scc[j]==k&&col[j]+1==rec[k][ti][tj]) printf("%d ", j);
}
if (rec[k][ti][tj]==1) {
ti-=a[k];
tj-=b[k];
} else if (rec[k][ti][tj]==2) {
ti-=b[k];
tj-=a[k];
}
}
return 0;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: