jzoj3782 組隊

Description

你的任務是將一羣人分到兩個隊伍中,使得:
1、每個人都屬於一個隊伍。
2、每個隊伍至少有一個人。
3、每個隊伍的任意一個人都認識其他人。
4、兩支隊伍的人數儘可能接近。
這個任務可能有多組解,你可以輸出任意一種。
注意:認識是單向的且沒有傳遞性。

Input

第一行爲一個整數N,表示總人數。
接下來爲N行,每行多個整數x,第i + 1行描述編號爲i的人認識x。每行以 0 結尾。

Output

如果無解輸出−1;否則輸出包含兩行, 每行的第一個數字表示該隊伍的總人數k,後面接着k個數字,表示被分到該隊伍的人。

Sample Input

5
2 3 5 0
1 4 5 3 0
1 2 5 0
1 2 3 0
4 3 2 1 0

Sample Output

3 1 3 5
2 2 4

Data Constraint

對於分值爲 30%的數據,N <= 15
對於剩餘分值爲 70%的數據,N <= 100

Solution

我們先把不能相連的弄出來
那顯然他們要放在不同的集合
這樣子搞一搞之後
我們就可以dp了
設一個0/1狀態f[h][i][j]表示做完前h個小團塊 第一個集合放i個 第二個集合放j個是否可行
dp的時候保留一下方案即可

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int n,i,j,stm,h,k,cnt1,cnt2,a,b,f[105][105][105],x,y,xx,yy,k1,k2,z;
int aa[105][105],bz[105],g[105][2],un[105][105],pr[105],w[105],w1[105];
struct edge{
  int x,y;  
} bf[105][105][105];
int read(){
    int sum=0;
    char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9'){
        sum=sum*10+c-'0';
        c=getchar();} 
    return sum;
}
void dfs(int x){
    int i,y;
    fo(i,1,un[x][0]){
        y=un[x][i];
        if (bz[y]){
            if (bz[y]==bz[x]) { printf("-1\n"); exit(0);}
        } else {
            bz[y]=(bz[x]==stm)?stm+1:stm;
            if (bz[y]==stm) cnt1++; else cnt2++;
            dfs(y);}
    }
}
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    n=read();
    fo(i,1,n){
        k=read();
        while (k) aa[i][k]=1,k=read();}
    fo(i,1,n)
      fo(j,1,n)
        if (i!=j&&(!aa[i][j]||!aa[j][i])) un[i][++un[i][0]]=j;
    fo(i,1,n){
        if (bz[i]) continue;
        stm+=2,cnt2=0,cnt1=1,bz[i]=stm,dfs(i);
        g[++h][0]=cnt1,g[h][1]=cnt2;
        pr[h]=stm;}
    f[0][0][0]=1;
    fo(i,1,h)
      fo(a,0,n)
        fo(b,0,n) {
          if (a+g[i][0]<=n&&b+g[i][1]<=n){
            f[i][a+g[i][0]][b+g[i][1]]|=f[i-1][a][b];
            if (f[i-1][a][b]) {
                bf[i][a+g[i][0]][b+g[i][1]].x=a;
                bf[i][a+g[i][0]][b+g[i][1]].y=b;}
          }
          if (a+g[i][1]<=n&&b+g[i][0]<=n){
            f[i][a+g[i][1]][b+g[i][0]]|=f[i-1][a][b];
            if (f[i-1][a][b]){
                bf[i][a+g[i][1]][b+g[i][0]].x=a;
                bf[i][a+g[i][1]][b+g[i][0]].y=b;}
          }
    }
    fd(i,n/2,1)
      if (f[h][i][n-i]){
        x=i,y=n-i;
        fd(j,h,1){
            xx=bf[j][x][y].x,yy=bf[j][x][y].y;
            k1=pr[j],k2=k1+1;
            if (x-xx==g[j][1]) swap(k1,k2);
            fo(z,1,n) if (bz[z]==k1) w[++w[0]]=z;
              else if (bz[z]==k2) w1[++w1[0]]=z;
            x=xx,y=yy;
          }
          fo(j,0,w[0]) printf("%d ",w[j]);
          printf("\n");
          fo(j,0,w1[0]) printf("%d ",w1[j]);
          printf("\n");
          return 0;
      }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章