OUC_Summer Training_ DIV2_#16 725

今天做了这两道题真的好高兴啊!!我一直知道自己很渣,又贪玩不像别人那样用功,又没有别人有天赋。所以感觉在ACM也没有学到什么东西,没有多少进步。但是今天的B题告诉我,进步虽然不明显,但是只要坚持努力的学习,改变就会默默发生啦~真的好高兴,感觉自己又有了动力!自己现在虽然还不会什么算法,都是三脚猫功夫,但是已经真切的感觉到自己已经会用一点算法的思想了,哎呀我也不知道怎么说好,总之就是看到了自己的改变。

A - Array
Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u

Description

Vitaly has an array of n distinct integers. Vitaly wants to divide this array into three non-empty sets so as the following conditions hold:

  1. The product of all numbers in the first set is less than zero ( < 0).
  2. The product of all numbers in the second set is greater than zero ( > 0).
  3. The product of all numbers in the third set is equal to zero.
  4. Each number from the initial array must occur in exactly one set.

Help Vitaly. Divide the given array.

Input

The first line of the input contains integer n (3 ≤ n ≤ 100). The second line contains n space-separated distinct integers a1, a2, ..., an(|ai| ≤ 103) — the array elements.

Output

In the first line print integer n1 (n1 > 0) — the number of elements in the first set. Then print n1 numbers — the elements that got to the first set.

In the next line print integer n2 (n2 > 0) — the number of elements in the second set. Then print n2 numbers — the elements that got to the second set.

In the next line print integer n3 (n3 > 0) — the number of elements in the third set. Then print n3 numbers — the elements that got to the third set.

The printed sets must meet the described conditions. It is guaranteed that the solution exists. If there are several solutions, you are allowed to print any of them.

Sample Input

Input
3
-1 2 0
Output
1 -1
1 2
1 0
Input
4
-1 -2 -3 0
Output
1 -1
2 -3 -2
1 0
先来一道简单的题,题意是,给出一个数组,把数组中的数分为3个部分,要求第一个部分的乘积(我一开始真的不知道product是乘积的意思啊)小于0,第二部分乘积大于0,第三部分乘积等于0.
我的做法是:先将读入的数按> < =分在3个数组中,然后再做进一步处理。不过我看到还有一种做法,将数组读入后排序,第一个数(一定小于0) 输出,最后一个数,如果是正数输出是0输出2个负数,把剩下的输出。下面是我的方法的代码。
#include<stdio.h>
int main()
{
    int a1[100],a2[100],a3[100];
    int N,i,n1 = 0,n2 = 0,n3 = 0;
    int a;
    scanf("%d",&N);
    for(i = 0;i < N;i++)
    {
        scanf("%d",&a);
        if(a < 0)a1[n1++] = a;
        else if(a > 0)a2[n2++] = a;
        else a3[n3++] = a;
    }
    if(n1 % 2 == 0)a3[n3++] = a1[--n1];
    if(n2 == 0)
    {
        a2[n2++] = a1[--n1];
        a2[n2++] = a1[--n1];
    }
    printf("%d ",n1);
    for(i = 0;i < n1;i++)printf("%d ",a1[i]);
    printf("
%d ",n2);
    for(i = 0;i < n2;i++)printf("%d ",a2[i]);
    printf("
%d ",n3);
    for(i = 0;i < n3;i++)printf("%d ",a3[i]);
    printf("
");
    return 0;
}
View Code

B - Coach
Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u

Description

A programming coach has n students to teach. We know that n is divisible by 3. Let's assume that all students are numbered from 1 to n, inclusive.

Before the university programming championship the coach wants to split all students into groups of three. For some pairs of students we know that they want to be on the same team. Besides, if the i-th student wants to be on the same team with the j-th one, then the j-th student wants to be on the same team with the i-th one. The coach wants the teams to show good results, so he wants the following condition to hold: if the i-th student wants to be on the same team with the j-th, then the i-th and the j-th students must be on the same team. Also, it is obvious that each student must be on exactly one team.

Help the coach and divide the teams the way he wants.

Input

The first line of the input contains integers n and m (3 ≤ n ≤ 48. Then follow m lines, each contains a pair of integers ai, bi (1 ≤ ai < bi ≤ n) — the pair ai, bi means that students with numbers ai and bi want to be on the same team.

It is guaranteed that n is divisible by 3. It is guaranteed that each pair ai, bi occurs in the input at most once.

Output

If the required division into teams doesn't exist, print number -1. Otherwise, print  lines. In each line print three integers xiyizi (1 ≤ xi, yi, zi ≤ n) — the i-th team.

If there are multiple answers, you are allowed to print any of them.

Sample Input

Input
3 0
Output
3 2 1 
Input
6 4
1 2
2 3
3 4
5 6
Output
-1
Input
3 3
1 2
2 3
1 3
Output
3 2 1 
就是这个题!!让我大涨信心。题意是:有一群人要组队,如果a想和b一队,b就得和a一队。给出组队愿望,打印出一组符合的组队形式,如果不能就输出-1.
我是这样想的,这样的题应该不假思索的用并查集吧,一开始我也用了,但是最后输出的时候好麻烦啊,因为,例如如果输入关系1 2 1 3 这样用并查集做f[1] = 2,f[2] = 3,f[3] = 3.输出的时候为了找到同一个一队的人就不是很方便了,而且还会有人没有发表过意见,这种情况处理起来也不是很容易(说到底还是我渣,大神们用并查集写的代码也很简单)于是我就换了一种方法,好在最大的人数只有48 3重循环也不怕!我做的改动是使得同一个队的父亲节点只有一个(暂且叫他队长好了)即f[1] = 3;f[2] = 3;f[3] = 3;然后为了处理无法组队的情况又开了一个数组q,用于记录第i个人所在的队已经有q[i]个人了,最后还是错了两次,一次是错在测试样例6 3 1 2 3 4 5 6 上,这样一组测试样例应该输出-1才对,我却输出1 2 3 4 5 6 因为我没有在最后再一次检验是否能够组队成功,一次错在 9 3 4 5 6 7 8 9上因为我一开始遇见没有意见的人就从前向后遍历找到一个没有组队的或者队里不满的就组队。这样的结果就是1 2 3 4 5 6 7 8 9显然错了,于是我又让没有意见的人先加入人数不满的队中,剩下的再自己组队。这样就过了。
另一个新发现是 CF上可以看测试数据,所以我的B题才有机会改好,但是转念一想,能看测试数据当然好,但是看了测试数句后再改代码的话难免有点亡羊补牢的感觉,也少不了拆东墙补西墙的嫌疑,就害怕会按了葫芦起了瓢,无奈测试样例毕竟有限过了也不代表方法一定就对了。但世界上又有什么是绝对正确的呢?
#include<stdio.h>
int main()
{
    int q[52]  = {0};
    int f[52];
    int N,T,i,j,k;
    scanf("%d%d",&N,&T);
    int a,b;
    int flag = 0;
    for(i = 1;i <= N;i++)f[i] = i;
    while(T--)
    {
        scanf("%d%d",&a,&b);
        if(q[a] == 0 && q[b] == 0)q[a] = 2;
        else if(q[a]== 0 &&q[b] != 0)q[a] = q[b]+1;
        else if(q[a] != 0 && (f[a] != b&&f[b]!= a)) q[a]++;
        q[b] = q[a];
        if(f[a] == a)
        {
            for(i = 1;i <= N;i++)
            {
                if(f[i] == a)f[i] = b;
            }
            for(i = 1;i <= N;i++)
            {
                if(f[i] == b)q[i] = q[a];
            }
        }
        else {q[f[a]] = q[a];f[f[a]] = b;f[a] = b;}
    }
    for(i = 1;i <= N;i++)if(q[i] > 3)
    {flag = 1;break;}
    if(flag == 1)printf("-1
");
    else
    {
        for(i = 1;i <= N;i++)//处理有人没有意见的情况,优先补满缺一个人的队
        {
            if(q[i] == 0)//没有意见
            {
                for(j = 1;j <= N;j++)
                {
                    if(j == i)continue;
                    if(q[j] == 2)//该组已经有2个人
                    {
                        q[j]=q[i] = 3;
                        if(f[j] == j)//这个人是队长
                        {    for(k = 1;k <= N;k++)
                            {
                                if(f[k] == j)q[k] = 3;//找到队员
                            }
                            f[i] = j;
                        }
                        else {q[f[j]] = 3;f[i] = f[j];}
                        break;
                    }
                }
            }
        }
        int c,num= 0;
        for(i = 1;i <= N;i++)
        {
            if(q[i] == 0)
            {
                if(num == 0)
                {num++;a = i;continue;}
                if(num == 1)
                {num++;b = i;continue;}
                if(num == 2)
                {f[a] = f[b] = i;q[a] = q[b] = q[i] = 3;num = 0;continue;}
            }
        }
        for(i = 1;i <= N;i++)
        {
            if(q[i] != 3){printf("-1
");return 0;}
        }
        for(i = 1;i <= N;i++)
        {
            if(f[i] == i)
            {    for(j = 1;j <= N;j++)
                {
                    if(f[j] == i)
                    printf("%d ",j);
                }
                printf("
");
            }
        }
    }
    return 0;
}
View Code

递归的并查集代码是father是全局变量,最后两句是写在主函数里的维基百科讲的挺细。

int find(int x)
{
if(father[x]!=x) father[x]=find(father[x]);
return father[x];
}
scanf("%d%d",&a,&b);
a=find(a),b=find(b);father[a]=b;

原文地址:https://www.cnblogs.com/lwy-kitty/p/3216550.html