noip模拟赛 都市

分析:是一道非常有意思的题,30分的暴力的话枚举每个位置是什么数,然后排个序,用map判一下重就好了,比较麻烦.

      满分做法显然不可能讨论每个位置所有的情况,肯定是有规律的,现将这n*(n-1)/2个数排序,假设N个数组成的排列是a1,a2,......,aN,并且a1≤a2≤......≤aN.那么最小的那个和肯定是a1 + a2,次小的那个和肯定是a1 + a3,第三小的就不好确定了,如果能把a2 + a3给求出来,那么就能把a1,a2,a3给解出来,所以枚举a2+a3是哪一个,把a1+a2,a2+a3,a1+a3给求出来后从原数组中删掉,那么剩下的最小的数就是a1+a4,a4可以解出来,再把a2,a3与a4相加,把得到的数给删掉,再对a5进行同样的操作,就能得到整个序列了,所以枚举a2+a3的位置,并check一下就好了.

     check的时候要先判断这个ai+a1在原数组中存不存在,是否都已经被占用了,要判断好所有的情况才行.

30分暴力:

 

#include <cstdio>
#include <map>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n, cnt, a[20], flag[20], ans,tot,tag[20];
int p[20],cnt2,anss[100010][7];

map<long long,bool> vis;

struct node
{
    int a[12];
    node()  { memset(a, 0, sizeof(a)); }
}e[10010];

bool cmp(node x,node y)
{
    for (int i = 1; i <= n; i++)
        if (x.a[i] > y.a[i])
        return 1;
    return 0;
}

void print()
{
    for (int i = 1; i <= n; i++)
        printf("%d ", flag[i]);
    printf("\n");
}

void solve()
{
    long long res = 0;
   //print();
    memcpy(tag,flag,sizeof(flag));
    sort(tag + 1,tag + 1 + n);
    for (int i = 1; i <= n; i++)
        res = (res * 10 + tag[i]);
    if (vis[res])
        return;
    vis[res] = 1;
    cnt2 = 0;
    for (int i = 2; i <= n; i++)
        for (int j = 1; j < i; j++)
            p[++cnt2] = flag[i] + flag[j];
            sort(p + 1, p + 1 + cnt2);
    for (int i = 1; i <= cnt; i++)
        if (p[i] != a[i])
            return;
    tot++;
    for (int i = 1; i <= n; i++)
        e[tot].a[i] = tag[i];
    ans++;
}

void dfs(int dep)
{
    if (dep == n + 1)
    {
        solve();
        return;
    }
    for (int i = 10; i >= 1; i--)
    {
        flag[dep] = i;
        dfs(dep + 1);
    }
}

int main()
{
    scanf("%d", &n);
    cnt = n * (n - 1) / 2;
    for (int i = 1; i <= cnt; i++)
        scanf("%d", &a[i]);
    sort(a + 1,a + 1 + cnt);
    dfs(1);
    printf("%d\n", ans);
    sort(e + 1,e + 1 + tot,cmp);
    for (int i = 1; i <= tot; i++)
    {
        for (int j = 1; j <= n; j++)
            printf("%d ", e[i].a[j]);
        printf("\n");
    }

    return 0;
}

 

正解:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

using namespace std;

int n, a[100010], cnt, tot, ans[10010][310], val[310];
bool vis[100010];

void solve(int x)
{
    memset(vis, 0, sizeof(vis));
    int temp = (a[1] + a[2] + a[x]) / 2;
    val[3] = temp - a[1];
    val[2] = temp - a[2];
    val[1] = temp - a[x];
    vis[1] = vis[2] = vis[x] = 1;
    int cur = 3;
    for (int i = 4; i <= n; i++)
    {
        while (cur <= cnt && vis[cur])
            cur++;
        if (cur > cnt)
            return;
        val[i] = a[cur] - val[1];
        vis[cur] = 1;
        for (int j = 2; j < i; j++)
        {
            if (val[j] > val[i])
                return;
            int v = val[j] + val[i];
            int pos = lower_bound(a + 1, a + cnt + 1, v) - a;
            if (a[pos] != v)
                return;
            int pos2 = pos;
            while (pos2 && a[pos2] == a[pos])
                pos2--;
            pos2++;
            while (pos2 <= cnt && a[pos2] == a[pos] && vis[pos2])
                pos2++;
            if (a[pos2] != a[pos] || vis[pos2])
                return;
            vis[pos2] = 1;
        }
    }
    ++tot;
    for (int i = 1; i <= n; i++)
        ans[tot][i] = val[i];
}

int main()
{
    scanf("%d", &n);
    cnt = n * (n - 1) / 2;
    for (int i = 1; i <= cnt; i++)
        scanf("%d", &a[i]);
    sort(a + 1, a + 1 + cnt);
    for (int i = 3; i <= cnt; )
    {
        solve(i);
        int j = i;
        while (j <= cnt && a[j] == a[i])
            j++;
        i = j;
    }
    printf("%d\n", tot);
    for (int i = 1; i <= tot; i++)
    {
        for (int j = 1; j <= n; j++)
            printf("%d ", ans[i][j]);
        printf("\n");
    }

    return 0;
}

 

posted @ 2017-10-31 23:04  zbtrs  阅读(213)  评论(0编辑  收藏  举报