• codeforces B. Coach 解题报告


    题目链接:http://codeforces.com/problemset/problem/300/B

    题目意思:给出n个students(n%3 = 0),编号依次为1~n,接下来有m行,每行有两个数:a和b(1<=a, b <= n),表示号码a的人想和号码b的人一起组队。但最终每一组的人最多只能为3个,至于组里只有2个或根本不成组的人可以通过组队变成3个人。问最后每组是否恰好为3人(包括原来不需要组队和组队后的情况),是则输出每组人的编号,否则输出-1。

          一开始做的时候觉得像并查集,后来觉得做起来特别复杂,看了看tutorial,知道哪些情况为输出-1的:

          情况1:组里面超过3人    情况2:2人组人数 > 1人组的人数(不成组)

          根据这样硬用并查集来做,代码量非一般多!!!这就是不会算法的悲剧咯~~~

          我的思路:

          先用并查集来连边,保证大编号的指向最小编号的。

          接着统计一人组,二人组,三人组的人数(分别为c1,c2,c3),以判断结果为-1的两种情况。

          最后依次输出: 二人组 + 一人组,三人组,一人组 (除了三人组的情况其他两种都要组合)

         (以后学好dfs一定要写条简短的代码,呜呜呜~~~整个晚上没了)

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <cstring>
      5 using namespace std;
      6 
      7 const int maxn = 48 + 5;
      8 int res[maxn], cnt[maxn], vis[maxn], vis1[maxn], vis2[maxn];
      9 
     10 int find(int x)
     11 {
     12     while (x != res[x])
     13         x = res[x];
     14     return x;
     15 }
     16 
     17 void merge(int x, int y)
     18 {
     19     int fx = find(x);
     20     int fy = find(y);
     21     if (fx > fy)
     22         res[fx] = fy;
     23     else
     24         res[fy] = fx;
     25 }
     26 
     27 int main()
     28 {
     29     int n, m, i, j, k, a, b;
     30     while (scanf("%d%d", &n, &m) != EOF)
     31     {
     32         for (i = 1; i <= n; i++)
     33             res[i] = i;
     34         for (i = 0; i < m; i++)
     35         {
     36             scanf("%d%d", &a, &b);
     37             merge(a, b);
     38         }
     39         memset(vis, 0, sizeof(vis));       
     40         memset(vis1, 0, sizeof(vis1));
     41         memset(cnt, 0, sizeof(cnt));
     42         int flag, c2, c1, c3, f;
     43         c1 = c2 = c3 = 0;
     44         for (i = 1; i <= n; i++)
     45         {
     46             flag = 1;
     47             if (res[i] == i)
     48             {
     49                 f = 0;
     50                 for (j = i+1; j <= n; j++)
     51                 {
     52                     if (res[j] == i)
     53                     {
     54                         cnt[i]++;
     55                         f = 1;    // 1 p num 的标记
     56                     }
     57                 }
     58                 if (cnt[i] == 2)  // 3 p num
     59                     c3++;
     60                 if (cnt[i] == 1)  // 2 p num
     61                 {
     62                     c2++;
     63                     vis1[i] = 1;
     64                 }
     65                 if (cnt[i] >= 3)    // 组里的人多于3个
     66                     flag = 0; 
     67                 if (!f)            //  1 p num
     68                 {
     69                     vis[i] = 1;
     70                     c1++;
     71                 }
     72             }
     73             if (!flag)
     74                 break;
     75         }
     76         if (c2 > c1 || !flag)
     77             printf("-1
    ");
     78         else         
     79         {  
     80             memset(vis2, 0, sizeof(vis2));
     81             for (i = 1; i <= n; i++)     // 2 p num + 1 p num
     82             {
     83                 if (res[i] == i && vis1[i])  // vis1[i] 保证是2 p num
     84                 {
     85                     printf("%d ", i);
     86                     vis2[i] = 1;        // sign used
     87                     for (j = i+1; j <= n; j++)
     88                     {
     89                         if (!vis[j] && res[j] == i)  // !vis[j]:保证先输出2 p num的人
     90                         {
     91                             vis2[j] = 1;
     92                             printf("%d ", j);
     93                             for (k = 1; k <= n; k++)  // 1 p
     94                             {
     95                                 if (res[k] == k && vis[k] && !vis2[k])  // vis[k]:1 p num 的人
     96                                 {
     97                                     printf("%d
    ", k);
     98                                     vis2[k] = 1;
     99                                     c1--;  // 每输出一次减去一个1 p num的人
    100                                     break;
    101                                 }
    102                             }
    103                         }
    104                     }
    105                 }
    106             }
    107             for (i = 1; i <= n; i++)     // 3 p num
    108             {
    109                 if (res[i] == i && !vis1[i] && !vis[i]) // !vis1[i]:保证不是2 p num;!vis[i]:保证不是1 p num
    110                 {
    111                     for (j = i; j <= n; j++)
    112                     {
    113                         if (res[j] == i && !vis[j]) 
    114                         {
    115                             printf("%d ", j);
    116                             vis2[j] = 1;
    117                         }
    118                     }
    119                     printf("
    ");
    120                 }
    121             }
    122             int count = 0;
    123             for (i = 1; i <= n && c1; i++)    // 剩下的 1 p num的人,每3个人合成1组
    124             {
    125                 if (!vis2[i])
    126                 {
    127                     printf("%d ", i);
    128                     c1--;
    129                     count++;
    130                     if (count % 3 == 0)
    131                         printf("
    ");
    132                 }
    133             }            
    134         }
    135     }
    136     return 0;
    137 }
    138             

        

  • 相关阅读:
    谷歌浏览器离线安装
    C语言restrict关键字的使用
    Win32编程中radiobutton的分组
    在SourceForge中建立开源项目
    [转载]Linux解压缩命令
    [转载]vim配置文件
    解决VC6在win7下打开文件崩溃问题
    gson解析复杂的json数据
    catch中return语句的执行时间
    踏出了学习clojure的第一步
  • 原文地址:https://www.cnblogs.com/windysai/p/3538528.html
Copyright © 2020-2023  润新知