题目链接: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一定要写条简短的代码,呜呜呜~~~整个晚上没了)

 #include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std; const int maxn = + ;
int res[maxn], cnt[maxn], vis[maxn], vis1[maxn], vis2[maxn]; int find(int x)
{
while (x != res[x])
x = res[x];
return x;
} void merge(int x, int y)
{
int fx = find(x);
int fy = find(y);
if (fx > fy)
res[fx] = fy;
else
res[fy] = fx;
} int main()
{
int n, m, i, j, k, a, b;
while (scanf("%d%d", &n, &m) != EOF)
{
for (i = ; i <= n; i++)
res[i] = i;
for (i = ; i < m; i++)
{
scanf("%d%d", &a, &b);
merge(a, b);
}
memset(vis, , sizeof(vis));
memset(vis1, , sizeof(vis1));
memset(cnt, , sizeof(cnt));
int flag, c2, c1, c3, f;
c1 = c2 = c3 = ;
for (i = ; i <= n; i++)
{
flag = ;
if (res[i] == i)
{
f = ;
for (j = i+; j <= n; j++)
{
if (res[j] == i)
{
cnt[i]++;
f = ; // 1 p num 的标记
}
}
if (cnt[i] == ) // 3 p num
c3++;
if (cnt[i] == ) // 2 p num
{
c2++;
vis1[i] = ;
}
if (cnt[i] >= ) // 组里的人多于3个
flag = ;
if (!f) // 1 p num
{
vis[i] = ;
c1++;
}
}
if (!flag)
break;
}
if (c2 > c1 || !flag)
printf("-1\n");
else
{
memset(vis2, , sizeof(vis2));
for (i = ; i <= n; i++) // 2 p num + 1 p num
{
if (res[i] == i && vis1[i]) // vis1[i] 保证是2 p num
{
printf("%d ", i);
vis2[i] = ; // sign used
for (j = i+; j <= n; j++)
{
if (!vis[j] && res[j] == i) // !vis[j]:保证先输出2 p num的人
{
vis2[j] = ;
printf("%d ", j);
for (k = ; k <= n; k++) // 1 p
{
if (res[k] == k && vis[k] && !vis2[k]) // vis[k]:1 p num 的人
{
printf("%d\n", k);
vis2[k] = ;
c1--; // 每输出一次减去一个1 p num的人
break;
}
}
}
}
}
}
for (i = ; i <= n; i++) // 3 p num
{
if (res[i] == i && !vis1[i] && !vis[i]) // !vis1[i]:保证不是2 p num;!vis[i]:保证不是1 p num
{
for (j = i; j <= n; j++)
{
if (res[j] == i && !vis[j])
{
printf("%d ", j);
vis2[j] = ;
}
}
printf("\n");
}
}
int count = ;
for (i = ; i <= n && c1; i++) // 剩下的 1 p num的人,每3个人合成1组
{
if (!vis2[i])
{
printf("%d ", i);
c1--;
count++;
if (count % == )
printf("\n");
}
}
}
}
return ;
}

codeforces B. Coach 解题报告的更多相关文章

  1. codeforces 31C Schedule 解题报告

    题目链接:http://codeforces.com/problemset/problem/31/C 题目意思:给出 n 个 lessons 你,每个lesson 有对应的 起始和结束时间.问通过删除 ...

  2. codeforces 499B.Lecture 解题报告

    题目链接:http://codeforces.com/problemset/problem/499/B 题目意思:给出两种语言下 m 个单词表(word1, word2)的一一对应,以及 profes ...

  3. codeforces 495C. Treasure 解题报告

    题目链接:http://codeforces.com/problemset/problem/495/C 题目意思:给出一串只有三种字符( ')','(' 和 '#')组成的字符串,每个位置的这个字符 ...

  4. codeforces 490B.Queue 解题报告

    题目链接:http://codeforces.com/problemset/problem/490/B 题目意思:给出每个人 i 站在他前面的人的编号 ai 和后面的人的编号 bi.注意,排在第一个位 ...

  5. CodeForces 166E -Tetrahedron解题报告

    这是本人写的第一次博客,学了半年的基础C语言,初学算法,若有错误还请指正. 题目链接:http://codeforces.com/contest/166/problem/E E. Tetrahedro ...

  6. codeforces 489A.SwapSort 解题报告

    题目链接:http://codeforces.com/problemset/problem/489/A 题目意思:给出一个 n 个无序的序列,问能通过两两交换,需要多少次使得整个序列最终呈现非递减形式 ...

  7. codeforces 485A.Factory 解题报告

    题目链接:http://codeforces.com/problemset/problem/485/A 题目意思:给出 a 和 m,a 表示第一日的details,要求该日结束时要多生产 a mod ...

  8. codeforces 483A. Counterexample 解题报告

    题目链接:http://codeforces.com/problemset/problem/483/A 题目意思:给出一个区间 [l, r],要从中找出a, b, c,需要满足 a, b 互质,b, ...

  9. codeforces 479C Exams 解题报告

    题目链接:http://codeforces.com/problemset/problem/479/C 题目意思:简单来说,就是有个人需要通过 n 门考试,每场考试他可以选择ai, bi 这其中一个时 ...

随机推荐

  1. Java 自定义序列化、反序列化

    1.如果某个成员变量是敏感信息,不希望序列化到文件/网络节点中,比如说银行密码,或者该成员变量所属的类是不可序列化的, 可以用 transient 关键字修饰此成员变量,序列化时会忽略此成员变量. c ...

  2. emacs 打开文件乱码

    emacs在win下写的文件在linux打开乱码 M-x set-language-environment RET   chinese-gb    改变当前编码 用当前编码重新打开 M-x rever ...

  3. fastscripT实现权限控制

    fastscripT权限控制 此处以FASTSCRIPT实现功能权限为例,用脚本实现数据权限也是很方便的. unit Unit1; interface uses Winapi.Windows, Win ...

  4. 【java】spring项目中 对entity进行本类间的克隆

    方法1: [使用spring自带BeanUtils实现克隆] [要求:需要被克隆的类实现Cloneable接口并且重写clone()方法] >例子: >>实体: package co ...

  5. 【转载】使用事件模型 & libev学习

    参考这篇文章: http://www.ibm.com/developerworks/cn/linux/l-cn-edntwk/ 这里面使用的是 libev ,不是libevent Nodejs就是采用 ...

  6. java数据库连接池简单实现

    package cn.lmj.utils; import java.io.PrintWriter; import java.lang.reflect.InvocationHandler; import ...

  7. UDP用户数据报协议和IP分组

    UDP总体的封装格式例如以下: 以下是8字节UDP首部: 当IP层依据协议字段把UDP报文向上传送到UDP模块后,UDP模块再依据port号将数据发送到对应的进程中,以此实现进程到进程间的通信. 16 ...

  8. 【每日Scrum】第二天(4.23) TD学生助手Sprint2站立会议

    站立会议 组员 昨天 今天 困难 签到 刘铸辉 (组长) 昨天觉得整个界面不适合后期功能扩展,所以进行了整体整改 今天主要看了多事件处理的内容然后改了下界面, 遇到的困难就是正在寻找用户交互性比较好的 ...

  9. Linaro/Yocto/Openwrt

    http://en.wikipedia.org/wiki/Linaro Linaro From Wikipedia, the free encyclopedia     This article ap ...

  10. 实现iOS7上tableView的切割线像iOS6中的效果

    iOS7上tableView的切割线左边短了一点,要实现和iOS6中的效果还是有方法的,UITableView头文件中个属性: @property (nonatomic)         UIEdge ...