• 组队


    【 问题描述】
    你的任务是将一群人分到 两个队伍中,使得:
    1、每个人都属于一个队伍。
    2、每个队伍至少有一个人。
    3、每个队伍的任意一个人都认识其他人。
    4、两支队伍的人数尽可能接近。
    这个任务可能有多组解,你可以输出 任意一种。
    注意:认识是单向的且没有传递性。
    【 输入格式 】
    从文件 teams.in 中读入数据。
    第一行为一个整数N,表示总人数。
    接下来为N行,每行多个整数x,第i + 1 行描述编号为i的人认识x。每行以 0 结尾。
    【 输出格式 】
    输出到文件 teams.out 中。
    如果无解输出−1;否则输出包含两行,每行的第一个数字表示该队伍的总人
    数k,后面接着k个数字,表示被分到该队伍的人。
    【 样例输入 】
    5
    2 3 5 0
    1 4 5 3 0
    1 2 5 0
    1 2 3 0
    4 3 2 1 0
    【 样例输出 】
    3 1 3 5
    2 2 4
    【 数据规模及约 定 】
    对于分值为 30%的数据 , N <= 15
    对于剩余分值为 70%的数据 , N <= 100

    首先考虑转化一下,正难则反

    将不互相认识的人连边,这样分队就变成了二分图匹配的过程

    是否有解直接黑白染色

    接下来对于每一个联通块

    分成黑白点两个部分,显然因为每一个人都要分队,所以所有黑点分一边,白点分一边

    所以就变成了给两队分配黑白点,使差值最小

    令f[j][k]表示A队有j个人,B队有k个人,如果该状态存在,则转移

    接下来枚举联通块i,黑点数s1,白点数s2

    (1)f[j+s1][k+s2]=1

    (2)f[j+s2][k+s1]=1

    记录转移的路径from[j][k]表示j,k状态由什么联通块转移来

    如果是第一种转移,那么from[j+s1][k+s2]=i

    否则,from[j+s2][k+s1]=i+cnt(联通块数量)

    之所以做区分是为了方便输出解

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<vector>
      6 using namespace std;
      7 struct Node
      8 {
      9     int next,to;
     10 } edge[500001];
     11 int head[501],num,cnt,from[501][501],n,map[501][501],flag,f[501][501];
     12 vector<int>g[2][501],a1,a2;
     13 int vis[501];
     14 void add(int u,int v)
     15 {
     16     num++;
     17     edge[num].next=head[u];
     18     head[u]=num;
     19     edge[num].to=v;
     20 }
     21 bool dfs(int x,int now)
     22 {
     23     int i;
     24     vis[x]=now;
     25     for (i=head[x]; i; i=edge[i].next)
     26     {
     27         int v=edge[i].to;
     28         if (vis[v]==-1)
     29             {if (!dfs(v,now^1)) return 0;}
     30             else if (now==vis[v]) return 0;
     31     }
     32     return 1;
     33 }
     34 void insert(int x,int now)
     35 {
     36     int i;
     37     vis[x]=now;
     38     g[now][cnt].push_back(x);
     39     for (i=head[x]; i; i=edge[i].next)
     40     {
     41         int v=edge[i].to;
     42         if (vis[v]<0)
     43             insert(v,now^1);
     44     }
     45 }
     46 void solve(int x,int y)
     47 {
     48     int i;
     49     while (x||y)
     50     {
     51         if (from[x][y]<=cnt)
     52         {
     53             int k=from[x][y];
     54             for (i=0; i<g[0][k].size(); i++) a1.push_back(g[0][k][i]);
     55             for (i=0; i<g[1][k].size(); i++) a2.push_back(g[1][k][i]);
     56             x-=g[0][k].size();
     57             y-=g[1][k].size();
     58         }
     59         else
     60         {
     61             int k=from[x][y]-cnt;
     62             for (i=0; i<g[1][k].size(); i++) a1.push_back(g[1][k][i]);
     63             for (i=0; i<g[0][k].size(); i++) a2.push_back(g[0][k][i]);
     64             x-=g[1][k].size();
     65             y-=g[0][k].size();
     66         }
     67     }
     68     cout<<a1.size()<<' ';
     69     for (i=0; i<a1.size(); i++)
     70         printf("%d ",a1[i]);
     71     cout<<endl;
     72     cout<<a2.size()<<' ';
     73     for (i=0; i<a2.size(); i++)
     74         printf("%d ",a2[i]);
     75     cout<<endl;
     76 }
     77 int main()
     78 {
     79     int i,x,j,k;
     80     cin>>n;
     81     for (i=1; i<=n; i++)
     82     {
     83         scanf("%d",&x);
     84         while (x)
     85         {
     86             map[i][x]=1;
     87             scanf("%d",&x);
     88         }
     89     }
     90     for (i=1; i<=n; i++)
     91         for (j=1; j<=n; j++)
     92             if (i!=j)
     93                 if (map[i][j]==0||map[j][i]==0) add(i,j);
     94     memset(vis,-1,sizeof(vis));
     95     flag=1;
     96     for (i=1; i<=n; i++)
     97         if (vis[i]==-1)
     98         {
     99             if (!dfs(i,0))
    100             {
    101                 flag=0;
    102                 break;
    103             }
    104         }
    105     if (flag==0)
    106     {
    107         cout<<-1;
    108         return 0;
    109     }
    110     memset(vis,-1,sizeof(vis));
    111     for (i=1; i<=n; i++)
    112         if (vis[i]==-1)
    113         {
    114             ++cnt;
    115             insert(i,0);
    116         }
    117     f[0][0]=1;
    118     for (i=1; i<=cnt; i++)
    119     {
    120         for (j=n; j>=0; j--)
    121             for (k=n; k>=0; k--)
    122                 if (f[j][k])
    123                 {
    124                     int s1=g[0][i].size(),s2=g[1][i].size();
    125                     if (f[j+s1][k+s2]==0)
    126                     {
    127                         f[j+s1][k+s2]=1;
    128                         from[j+s1][k+s2]=i;
    129                     }
    130                     if (f[j+s2][k+s1]==0)
    131                     {
    132                         f[j+s2][k+s1]=1;
    133                         from[j+s2][k+s1]=i+cnt;
    134                     }
    135                 }
    136     }
    137     for (i=0; i<=n; i++)
    138     {
    139         for (j=1; j<=n; j++)
    140             if (j+j+i==n)
    141                 if (f[j][j+i]||f[j+i][j])
    142                 {
    143                     if (f[j][j+i]) solve(j,j+i);
    144                     else solve(j+i,j);
    145                     return 0;
    146                 }
    147     }
    148     return 0;
    149 }
  • 相关阅读:
    noip2010 乌龟棋
    noip2010 机器翻译
    noip2009 靶形数独
    noip2009 最优贸易
    noip2009 Hankson的趣味题
    noip2009 潜伏者
    noi2010 能量采集
    八大排序算法(六) 快速排序
    八大排序算法(六) 快速排序
    Lesson 12 Nehe
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7719220.html
Copyright © 2020-2023  润新知