UVa 269 Counting Patterns 解题报告(暴力)

56 篇文章 0 订阅

    UVa上看不到题目了,可以在UVa Live上或者VJudge上看题目。这里贴个:

Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu

[]   [Go Back]   [Status]  

Description

Download as PDF


 Counting Patterns 

Let n and k be numbers with n > 0 and tex2html_wrap_inline36 . A configuration of the n-k-puzzle is an n-tuple with elements in the range tex2html_wrap_inline44 such that their sum is zero. Configurations are considered equivalent when they can be obtained from each other by (a) cyclic permutation of the tuple over one or more positions, (b) reversal of the tuple, (c) sign reversal of all elements, or (d) combinations of (a), (b), and (c). Equivalence classes are called patterns.

For instance, (0, 1, 1, -2) is a configuration of the 4-2-puzzle. Some equivalent configurations are: (a) (1, -2, 0, 1), (b) (-2, 1, 1, 0), (c) (0, -1, -1, 2), and (d) (-1, -1, 0, 2). Below is given a list of (the lexicographically largest) representatives of the 14 patterns of the 4-2-puzzle.

displaymath46

Your program computes the number of patterns for a sequence of n-k-puzzles. And output the list of patterns (represented by the largest one in the patterns), from lower order to higher one.

Input

The input consists of a sequence of pairs of integers n and k, which are separated by a single space. Each pair appears on a single line. The input is terminated by an end-of-file. The value for n + k is at most 12. Make sure that your algorithm is fantastic enough.

Output

The output contains a sequence of blocks, the fisrt line contain a single integer(x), representing the number of patterns for the corresponding n-k-puzzles in the input, and follow x lines, each one contain one pattern(from lower order to higher one). Print one blank line between two consecutive blocks. No blank line should appear at the end of the output.

Sample Input

8 0
4 2

Sample Output

1
(0,0,0,0,0,0,0,0)

14
(0,0,0,0)
(1,-1,1,-1)
(1,0,-1,0)
(1,0,0,-1)
(1,1,-1,-1)
(2,-2,2,-2)
(2,-1,0,-1)
(2,-1,1,-2)
(2,0,-2,0)
(2,0,-1,-1)
(2,0,0,-2)
(2,1,-2,-1)
(2,1,-1,-2)
(2,2,-2,-2)

[]   [Go Back]   [Status]  

    解题报告:求出所有的,n个绝对值不大于k的数的排列,排列的和为0。且对于一个排列,全部正负号翻转、排列顺序翻转、起点移动到末尾构造出来的新排列视为同一个排列。要求按照字典序打印所有的排列。

    刚开始的想法是:先构造出所有和为0的无序的n个数,根据这个来构造出所有可能的排列。不过TLE了。

    参考了神牛们的解题报告,模仿之……其思路是按照字典序构造出和为0的排列,检查对于所有可能的变换操作,该排列是否是最优的。是的话就记录下来。最后打印。简单暴力,但是很有效。代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <iomanip>
using namespace std;
#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define bit(n) (1LL<<(n))
typedef long long LL;
typedef unsigned long long ULL;
void work();
int main()
{
#ifdef ACM
//    freopen("in.txt", "r", stdin);
#endif // ACM
    work();
}

/***************************************************/

const int maxn = 101010;
int cnt;
int res[maxn][20];
int a[20], b[40];
int n, k;

bool bigger(int * a, int * b)
{
    ff(i, n) if(a[i] != b[i])
        return a[i] > b[i];
    return false;
}

void check()
{
    ff(i, n)
        b[i] = b[i+n] = a[i];
    ff(i, n) if(b[i] == a[0])
        if(bigger(b+i, a)) return;
    reverse(b, b+2*n);
    ff(i, n) if(b[i] == a[0])
        if(bigger(b+i, a)) return;

    ff(i, n)
        b[i] = b[i+n] = -a[i];
    ff(i, n) if(b[i] == a[0])
        if(bigger(b+i, a)) return;
    reverse(b, b+2*n);
    ff(i, n) if(b[i] == a[0])
        if(bigger(b+i, a)) return;

    memcpy(res[cnt++], a, sizeof(a));
}

void dfs(int pos, int sum)
{
    if(pos == n)
    {
        if(sum == 0)
            check();
        return;
    }

    if(abs(sum) > (n-pos)*a[0]) return;

    for(a[pos] = -a[0]; a[pos] <= a[0]; a[pos]++)
    {
        if(a[pos-1] == a[0] && a[pos] > a[1]) return;
        dfs(pos+1, sum + a[pos]);
    }
}

void work()
{
    int first = false;
    while(scanf("%d%d", &n, &k) == 2)
    {
        cnt = 1;
        for(a[0] = 1; a[0] <= k; a[0]++)
            dfs(1, a[0]);

        if(first) puts("");
        first = true;
        printf("%d\n", cnt);
        ff(i, cnt)
        {
            printf("(%d", res[i][0]);
            fff(j, 1, n-1) printf(",%d", res[i][j]);
            puts(")");
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值