首页 > 代码库 > [ACM] ZOJ 3844 Easy Task (模拟+哈希)

[ACM] ZOJ 3844 Easy Task (模拟+哈希)

Easy Task

Time Limit: 2 Seconds      Memory Limit: 65536 KB

You are given n integers. Your task is very easy. You should find the maximum integer a and the minimum integer b among these n integers. And then you should replace both a and bwith a-b. Your task will not be finished unless all the integers are equal.

Now the problem come, you want to know whether you can finish you task. And if you can finish the task, you want to know the final result.

Input

The first line of the input contain an integer T(T≤ 20) indicates the number of test cases.

Then T cases come. Each case consists of two lines. The first line is an integer n(2≤ n≤ 10) as the problem described. The second line contains n integers, all of them are no less than -100000 and no more than 100000.

Output

For each case you should print one line. If you can finish your task, you should print one of the n integers. Otherwise, you should print "Nooooooo!"(without quotes).

Sample Input

2
3
1 2 3
2
5 5

Sample Output

2
5

Author: CHEN, Zemin
Source: ZOJ Monthly, January 2015

解题思路:

题意为给定n个数(2<=n<=10),每个数的范围为 -100000到100000,有一种操作:找到这n个数中最大的数max,最小的数min,把这两个数都替换为 max-min , 重复这样的操作,直到这n个数完全相同,如果可以达到这样的目的,就输出最后那n个数中的其中一个(每个数都一样),如果不能,则输出 Nooooooo!。

n的范围很小,直接按照题意排序模拟即可,一开始觉得任何数据都可以达到目的,没有输出Nooooooo!的情况,写了一发,交上去,果断WA.后来和二师兄讨论,应该记录状态才对,一旦出现相同的状态,那么就不能达到目的,输出Nooooooo!。方法为哈希查找,每一个状态用包含这n个数的结构体来保存,关键字是这n个数的和,以n个数的和对一个大素取余作为关键字,10个数的最大和不超过100000*10,所以开辟这么大的结构体类型的vector数组,当出现一个新的状态时,就去该状态的和取余后的索引中的那些状态去比较,这样可以减少比较次数,因为一个状态和另一个状态相同,它们分别的元素之和取余后相等是大前提。

注意:n个元素和可能是负数,建立索引要加上mod变为正数.

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <cmath>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
using namespace std;
#define ll long long
const int mod=100000*10+1;
const int inf=0x3f3f3f3f;
const int maxn=12;
int num[maxn];
int n;
struct Node
{
    int a[maxn];
};
vector<Node>vc[mod+10];

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        for(int i=0;i<=mod;i++)
            vc[i].clear();
        Node tp;
        cin>>n;
        int sum=0;
        for(int i=0;i<n;i++)
        {
            cin>>num[i];
            sum+=num[i];
        }
        tp.a[n]=sum;
        sort(num,num+n);
        if(num[0]==num[n-1])
        {
            cout<<num[0]<<endl;
            continue;
        }
        for(int i=0;i<n;i++)
            tp.a[i]=num[i];
        vc[(tp.a[n]+mod)%mod].push_back(tp);
        int ans=inf;
        while(1)
        {
            int cha=num[n-1]-num[0];
            sum=sum-num[n-1]-num[0]+2*cha;//新的sum
            num[0]=cha,num[n-1]=cha;
            sort(num,num+n);
            if(num[0]==num[n-1])
            {
                ans=num[0];
                break;
            }
            tp.a[n]=sum;
            for(int i=0;i<n;i++)
                tp.a[i]=num[i];
            bool ok=0;
            int idx=(tp.a[n]+mod)%mod;//去相应的索引中去找看是否有相同的状态
            for(int i=0;i<vc[idx].size();i++)
            {
                    int j;
                    for(j=0;j<n;j++)
                    {
                        if(tp.a[j]!=vc[idx][i].a[j])
                            break;
                    }
                    if(j==n)
                    {
                        ok=1;//找到了!
                        break;
                    }
            }
            if(ok==1)
                break;
            vc[idx].push_back(tp);
        }
        if(ans!=inf)
            cout<<ans<<endl;
        else
            cout<<"Nooooooo!"<<endl;
    }
    return 0;
}



[ACM] ZOJ 3844 Easy Task (模拟+哈希)