分类: OI路程

  • NOIP 2008 提高组 双栈排序 解体报告

      这个题目我的思路很简单,就是读入一个数据,判断是否小于s1的顶元素,如果是则讲数据压入s1,否则该数据是否小于s2的顶元素,如果是则将它压入栈s2。然后再判断s1的顶是否等于当前需要输出的值(就是安顺序来是不是对的),如果是就输出b。再同样判断s2,如果是就输出d。
      很可惜,只有30分,代码如下:
    #include <stdio.h>
    int num[1000];
    int s1[1000], s2[1000];
    int t1, t2;
    char ans[2000];
    int len;

    void add(char ch)
    {
            ans[len++] = ch;
    }

    int main(void)
    {
            int n;
            int i, j, r, t;
            scanf("%d", &n);
            for(i = 0; i < n; i++){
                    scanf("%d", &num[i]);
            }
            s1[0] = s2[0] = 10000;
            for(i = 1, j = 0; i <= n;){
                    r = j;
                    if(s1[t1] > num[j] && j < n){
                            s1[++t1] = num[j++];
                            add(‘a’);
                    }else if(s2[t2] > num[j] && j < n){
                            s2[++t2] = num[j++];
                            add(‘c’);
                    }
                    t = i;
                    if(s1[t1] == i){
                            t1–;
                            add(‘b’);
                            i++;
                    }
                    if(s2[t2] == i){
                            t2–;
                            i++;
                            add(‘d’);
                    }
                    if(t == i && r == j){
                            printf("0\n");
                            return 0;
                    }
            }
            for(i = 0; i < 2  n; i++){
                    if(i != 0){
                            printf(" ");
                    }
                    printf("%c", ans[i]);
            }
            printf("\n");
            return 0;
    }
      继续学习中。。
      额, 照着网上一个人抄的(当然是在理解的前提下, 再自己徒手打出来的.), 竟然没有AC, 然后试了试他自己的代码, 也没AC
      思路是这样的, 对于这样的数据i < j < k 且 num[k] < num[i] < num[j] 的情况下,i和j一定不能在同一个栈中,不然就是无解的情况,你想想啊,如果小的先入栈,大的又入栈,这能有解码?所以这里使用了二分图染色的算法,具体的解释看这位大牛和另一位的Blog: 
      http://www.byvoid.com/blog/noip2008-twostack/

      http://zhc105.info/blog/2010/06/双栈排序.html
      下面那个是90分的代码,上面那个是100分的代码。
      先贴代码吧:
    #include <stdio.h>
    #define minnum(a, b) ((a)<(b)?(a):(b))
    int num[1000];
    int min[1000];
    int map[1000][1000];
    int count[1000];
    int color[1000];

    void add(int i, int j)
    {
            map[i][count[i]++] = j;
    }

    int fill(int i, int c)
    {
            int j, t;
            color[i] = c;
            for(j = 0; j < count[i]; j++){
                    t = map[i][j];
                    if(color[t] == –1 && !fill(t, c ^ 1)){
                            return 0;
                    }else if(color[t] == c){
                            return 0;
                    }
            }
            return 1;
    }

    int s1[1000], s2[1000];
    int t1, t2;

    int main(void)
    {
            int n;
            int i, j;
            char 
    tmp;
            memset(min, 0x7F, sizeof(min));
            memset(color, 0xFF, sizeof(color));
            scanf("%d", &n);
            for(i = 0; i < n; i++){
                    scanf("%d", &num[i]);
            }
            for(i = n – 1; i >= 0; i–){
                    min[i] = minnum(min[i + 1], num[i]);
            }
            for(i = 0; i < n; i++){
                    for(j = i + 1; j < n; j++){
                            if(num[i] < num[j] && num[i] > min[j]){
                                    add(i, j);
                                    add(j, i);
                            }
                    }
            }
            for(i = 0; i < n; i++){
                    if(color[i] == –1){
                            if(!fill(i, 0)){
                                    printf("0\n");
                                    return 0;
                            }
                    }
            }
            j = 0;
            tmp = "";
            for(i = 1; i <= n; ){
                    if(s1[t1] == i){
                            printf("%sb", tmp);
                            t1–, i++;
                            continue;
                    }
                    if(s2[t2] == i && (j >= n || color[j])){
                            printf("%sd", tmp);
                            t2–, i++;
                            continue;
                    }
                    if(!color[j]){
                            printf("%sa", tmp);
                            tmp = " ";
                            s1[++t1] = num[j++];
                    }else{
                            printf("%sc", tmp);
                            tmp = " ";
                            s2[++t2] = num[j++];
                    }
            }
            printf("\n");
    //      getch();
            return 0;
    }

      但是将上述代码稍加修改后,就能够AC了:
    #include <stdio.h>
    #define minnum(a, b) ((a)<(b)?(a):(b))
    int num[1000];
    int min[1001];
    int map[1000][1000];
    int count[1000];
    int color[1000];

    void add(int i, int j)
    {
            map[i][count[i]++] = j;
    }

    int fill(int i, int c)
    {
            int j, t;
            color[i] = c;
            for(j = 0; j < count[i]; j++){
                    t = map[i][j];
                    if(color[t] == –1 && !fill(t, c ^ 1)){
                            return 0;
                    }else if(color[t] == c){
                            return 0;
                    }
            }
            return 1;
    }

    int s1[1000], s2[1000];
    int t1, t2;

    int main(void)
    {
            int n;
            int i, j;
            char *tmp;
            scanf("%d", &n);
            for(i = 0; i < n; i++){
                    scanf("%d", &num[i]);
            }
            min[n] = 10001;
            for(i = n – 1; i >= 0; i–){
                    min[i] = minnum(min[i + 1], num[i]);
            }
            for(i = 0; i < n; i++){
                    for(j = i + 1; j < n; j++){
                            if(num[i] < num[j] && num[i] > min[j]){
                                    add(i, j);
                                    add(j, i);
                            }
                    }
            }

            for(i = 0; i < n; i++){
                    color[i] = –1;
            }

            for(i = 0; i < n; i++){
                    if(color[i] == –1){
                            if(!fill(i, 0)){
                                    printf("0\n");
                                    return 0;
                            }
                    }
            }
            j = 0;
            tmp = "";
            for(i = 1; i <= n; ){
                    if(s1[t1] == i){
                            printf("%sb", tmp);
                            t1–, i++;
                            continue;
                    }
                    if(s2[t2] == i && (j >= n || color[j])){
                            printf("%sd", tmp);
                            t2–, i++;
                            continue;
                    }
                    if(!color[j]){
                            printf("%sa", tmp);
                            tmp = " ";
                            s1[++t1] = num[j++];
                    }else{
                            printf("%sc", tmp);
                            tmp = " ";
                            s2[++t2] = num[j++];
                    }
            }
            printf("\n");
    //      getch();
            return 0;
    }

  • NOIP 2008 提高组 传纸条 解题报告

      这题我以前就看过,一直不会做,后来看到别人说双线程动态规划,我以为是多么多么的神奇的一个东西,把它看的和Linux源码一样神奇了,现在学了之后也就是简单的DP,我用的四维DP,别人都说是三维,我先用四维做,以后再考虑三维(也许不会再考虑这一题了咯。)
      我的方程如下:f[a][b][c][d] = max(f[a – 1][b][c – 1][d], f[a][b – 1][c – 1][d], f[a – 1][b][c][d – 1], f[a][b – 1][c][d – 1]) + map[a][b] + map[c][d].
      a,b代表第一个线程(说线程夸张了一点),c,d代表第二个线程的坐标,map就是对应坐标的值。
      代码如下:
    #include <stdio.h>
    #define max(a, b) ((a)>(b)?(a):(b))
    int f[51][51][51][51];
    int map[51][51];
    int m, n;
    int s[4];

    volatile void test(int a, int b, int c, int d, int t)
    {
            if(a < 0 || b < 0 || c < 0 || d < 0){
                    return;
            }
            
    t = max(*t, f[a][b][c][d]);
    }

    void dp(void)
    {
            int a = s[0], b = s[1], c = s[2], d = s[3];
            int t = 0;
            test(a – 1, b, c – 1, d, &t);
            test(a – 1, b, c, d – 1, &t);
            test(a, b – 1, c, d – 1, &t);
            test(a, b – 1, c – 1, d, &t);
            f[a][b][c][d] = t + map[a][b] + map[c][d];
    }

    void srch(int now)
    {
            int i, k;
            if(now == 4){
                    if(s[0] != s[2] || s[1] != s[3]){
                            dp();
                    }
                    return;
            }
            if(now & 1){
                    k = n;
            }else{
                    k = m;
            }
            for(i = 1; i <= k; i++){
                    s[now] = i;
                    srch(now + 1);
            }
    }

    int main(void)
    {
            int i, j, k, l;
            scanf("%d%d", &m, &n);
            for(i = 1; i <= m; i++){
                    for(j = 1; j <= n; j++){
                            scanf("%d", &map[i][j]);
                    }
            }
            f[1][1][1][1] = map[1][1];
            srch(0);

            s[0] = s[2] = m;
            s[1] = s[3] = n;
            dp();

            printf("%d\n", f[m][n][m][n]);
            return 0;
    }

  • USACO 3.3.3. Shopping Offers 商店购物

      一道DP题,DP的方程很简单:
      f[a][b][c][d][e] = min(f[a][b][c][d][e], f[a – cost[0][0]][b – cost[0][1]][c – cost[0][2]][d – cost[0][3]][e – cost[0][4]], f[a – cost[1][0]][b – cost[1][1]][c – cost[1][2]][d – cost[1][3]][e – cost[1][4]]…);
      代码如下:
    /
    LANG: C
    ID: zqynux2
    PROG: shopping
    /
    #include <stdio.h>
    #define min(a, b) ((a)<(b)?(a):(b))
    struct you{
            int len;
            struct thing{
                    int id, num;
            }buy[5];
            int priece;
    }buy[99];
    int money[6];
    int num[6];
    int good[1000];
    int f[6][6][6][6][6];
    int n, m;

    int s[6];

    void init(int now)
    {
            int i;
            if(now == m){
                    for(i = 0; i < m; i++){
                            f[s[0]][s[1]][s[2]][s[3]][s[4]] += money[i + 1] s[i];
                    }
                    return;
            }
            for(i = 0; i <= 5; i++){
                    s[now] = i;
                    init(now + 1);
            }
    }

    void deal(int now)
    {
            int used[6];
            int i;
            memset(used, 0, sizeof(used));
            for(i = 0; i < buy[now].len; i++){
                    used[good[buy[now].buy[i].id]] += buy[now].buy[i].num;
            }
            if(used[0] != 0){
                    return;
            }
            for(i = 0; i < 5; i++){
                    if(used[i + 1] > s[i]){
                            return;
                    }
            }
            f[s[0]][s[1]][s[2]][s[3]][s[4]] = min(f[s[0]][s[1]][s[2]][s[3]][s[4]], 
                    f[s[0] – used[1]][s[1] – used[2]][s[2] – used[3]][s[3] – used[4]][s[4] – used[5]]
                    + buy[now].priece);
    }

    void srch(int now)
    {
            int i;
            if(now == m){
                    for(i = 0; i < n; i++){
                            deal(i);
                    }
                    return;
            }
            for(i = 0; i <= 5; i++){
                    s[now] = i;
                    srch(now + 1);
                    //写成了init 
            }
    }

    int main(void)
    {
            int i, j;
            freopen("shopping.in", "r", stdin);
            freopen("shopping.out", "w", stdout);
            scanf("%d", &n);
            for(i = 0; i < n; i++){
                    scanf("%d", &buy[i].len);
                    for(j = 0; j < buy[i].len; j++){
                            scanf("%d%d", &buy[i].buy[j].id,
                                            &buy[i].buy[j].num);
                    }
                    scanf("%d", &buy[i].priece);
            }
            scanf("%d", &m);
            for(i = 1; i <= m; i++){
                    scanf("%d%d%d", &j, &num[i], &money[i]);
                    good[j] = i;
            }

            init(0);                       / 将价格进行初始化 /
            srch(0);                       /
     DP */

            printf("%d\n", f[num[1]][num[2]][num[3]][num[4]][num[5]]);
            return 0;
    }

  • NOIP 2008 笨小猴 解题报告

      这个题目很简单,不过我也提交了两次。。问题见注释。
    #include <math.h>
    #include <stdio.h>
    #include <string.h>
    char str[101];
    int count[26];

    int isprime(int n)
    {
            int li;
            int i;
            if(n == 0 || n == 1){
                    //0和1不算素数 
                    return 0;
            }
            li = sqrt(n);
            for(i = 2; i <= li; i++){
                    if(n % i == 0){
                            return 0;
                    }
            }
            return 1;
    }

    int main(void)
    {
            int i, len;
            int max = –1, min = 1000;
            int ans;
            scanf("%s", str);
            len = strlen(str);
            for(i = 0; i < len; i++){
                    count[str[i] – ‘a’]++;
            }
            for(i = 0; i < 26; i++){
                    if(max < count[i]){
                            max = count[i];
                    }
                    if(min > count[i] && count[i] != 0){
                                    //如果字符没有出现的话就不算 
                            min = count[i];
                    }
            }
            ans = max – min;
            if(isprime(ans)){
                    printf("Lucky Word\n");
                    printf("%d\n", ans);
            }else{
                    printf("No Answer\n0\n");
                            //忘记输出0了  
            }
    //      getch();
            return 0;
    }

  • NOIP 2008 火柴棒等式 解题报告

      刚刚拿到题目感觉非常容易,第一次提交,发现把数据写错了,6是6根火柴,我写的5根。第二次提交我发现题目不止是个位的运算,还可以十位,百位。。第三次提交,AC了,不过效率太慢了,代码如下:
    #include <stdio.h>
    int num[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
                        //数据写错了

    int count(int n)
    {
            int t = 0;
            if(n == 0){
                    t = num[0];
            }
            while(n){
                    t += num[n % 10];
                    n /= 10;
            }
            return t;
    }

    int main(void)
    {
            int n;
            int i, j;
            int ans = 0;
            scanf("%d", &n);
            for(i = 0; i <= 2000; i++){
                    for(j = 0; j <= 2000; j++){                           
                            if(count(i) + count(j) + count(i + j) + 4 == n){
                                    ans++;
                            }
                    }
            }
            printf("%d\n", ans);
            return 0;
    }
      后来看到七妹的代码,发现自己的代码太破了,本来我是想用数组记录一下的,后来发现这都不用。NOIP 2008 火柴棒等式 解题报告 - NeWorldMaker - My S-K-Y,修改后的代码如下:
    #include <stdio.h>
    int num[5001] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
                        //数据写错了
    int main(void)
    {
            int n;
            int i, j;
            int ans = 0;
            scanf("%d", &n);
            for(i = 10; i <= 5000; i++){
                    num[i] = num[i / 10] + num[i % 10];
            }
            for(i = 0; i <= 5000; i++){
                    for(j = 0; j <= 5000; j++){
                            if(i + j <= 5000 && num[i] + num[j] + num[i + j] + 4 == n){
                                    ans++;
                            }
                    }
            }
            printf("%d\n", ans);
            return 0;
    }

  • NOIP 2009 最优贸易 解题报告

      这题我纠结了三天,今天终于AC了,,辛苦死我了。。
      这题我看错了题目,连续两次。最后才弄清楚题目,就是两次搜索,第一次搜索所有的最小的价格,第二次搜索所有的最大的价格,然后就是枚举每一个节点的最大值-最小值。
      其中的数据结构是我偶然想到的,直接用一个数组表示,然后用另外一个数组进行标识每个都是哪个的邻接。
      思路真的没说清楚,我不想再说了,这题太难了(算法不难,空间压缩难。)。
    #include <stdio.h>
    #include <stdlib.h>
    #define MAX 100001
    #define minnum(a, b) ((a)<(b)?(a):(b))
    #define maxnum(a, b) ((a)>(b)?(a):(b))
    struct place{
            
    int x, y;
    }map[
    1000000];
    int inv[1000000], outv[1000000];
    /* 表示所有的的节点的入节点和出节点 */
    int len;
    int in[1000000], out[1000000];
    /* in[0] ~ in[1] 代表进节点1的的inv的下标. */
                    
    //上面的数组第一次都开小了, 
    int money[MAX];
    int max[MAX], min[MAX];
    int at[MAX];
    int n, m;
    int queue[MAX];
    int h, q;

    void enqueue(int x)
    {
            
    int t;
            t = q + 
    1;
            
    if(t > MAX){
                    t = 
    0;
            }
            
    if(t == h){
                    exit(-
    1);
            }
            queue[q] = x;
            q = t;
    }

    int exqueue(void)
    {
            
    int t, r;
            
    if(h == q){
                    exit(-
    1);
            }

            t = h + 1;
            
    if(t > MAX){
                    t = 
    0;
            }
            r = queue[h];
            h = t;
            
    return r;
            
    }

    void add(int i, int j)
    {
            map[len].x = i;
            map[len].y = j;
            in[j]++;
            out[i]++;
            len++;
    }

    int com1(const void *a, const void *b)
    {
            
    struct place i = *(struct place *)a, j = *(struct place *)b;
            
    return i.x – j.x;
    }

    int com2(const void *a, const void *b)
    {
            
    struct place i = *(struct place *)a, j = *(struct place *)b;
            
    return i.y – j.y;
    }

    void sort(int *a)
    {
            
    int t = 0, r;
            
    int i;
            
    for(i = 1; i <= n; i++){
                    r = a[i];
                    a[i] += t;
                    t += r;
            }
    }

    int main(void)
    {
            
    int i, j;
            
    int a, b, c;
            
    int t, ans;
            scanf(
    “%d%d“, &n, &m);
            
    for(i = 1; i <= n; i++){
                    scanf(
    “%d“, &money[i]);
            }
            
    for(i = 1; i <= m; i++){
                    scanf(
    “%d%d%d“, &a, &b, &c);
                    add(a, b);
                    
    if(c == 2){
                            add(b, a);
                    }
            }
            qsort(map, len, 
    sizeof(struct place), com1);           //对inv和outv赋值 
            
    for(i = 0; i < len; i++){
                    outv[i] = map[i].y;
            }
            qsort(map, len, 
    sizeof(struct place), com2);
            
    for(i = 0; i < len; i++){
                    inv[i] = map[i].x;
            }
            sort(in);                                               
    //对下标赋值 
            sort(out);

            for(i = 1; i <= n; i++){
                    min[i] = 
    1000000;
                    max[i] = 
    0;
            }

            enqueue(1); at[1] = 1;                         //搜索所有价格中最低的 
            
    while(h != q){
                    t = exqueue();
                    at[t] = 
    0;
                    
    for(i = out[t – 1]; i < out[t]; i++){
                            j = outv[i];
                            
    if(min[j] > min[t] || money[j] < min[j]){
                                    min[j] = minnum(money[j], min[t]);
                                    
    if(!at[j]){
                                            at[j] = 
    1;
                                            enqueue(j);
                                    }
                            }
                    }
            }
            enqueue(n); at[n] = 
    1;                         //搜索所有价格中最高的
            
    while(h != q){
                    t = exqueue();
                    at[t] = 
    0;
                    
    for(i = in[t – 1]; i < in[t]; i++){
                            j = inv[i];
                            
    if(max[j] < max[t] || money[j] > max[j]){
                                    max[j] = maxnum(money[j], max[t]);
                                    
    if(!at[j]){
                                            at[j] = 
    1;
                                            enqueue(j);
                                    }
                            }
                    }
            }

            ans = 0;
            
    for(i = 1; i <= n; i++){
                    
    if(max[i] – min[i] > ans){
                            ans = max[i] – min[i];
                    }
            }

            printf(“%d\n“, ans);
            
    return 0;
    }

  • NOIP2009 靶形数独 解题报告

      苦难的题目,我做着题只有一个想法:深搜,,暴力搜索!但是就连样例都超时了,我就直接找题解去了。
      网上找到一个题解,用位运算做的,大概看了下就开始仿造着写,去掉了感觉无用的功能(其实很有用),结果超时了。。。超时代码如下,75分。
    #include <stdio.h>
    #define getindex(t) ({\
            int i;\
            switch(t){\
            case 1:\
                    i = 0;\
                    break;\
            case 2:\
                    i = 1;\
                    break;\
            case 4:\
                    i = 2;\
                    break;\
            case 8:\
                    i = 3;\
                    break;\
            case 16:\
                    i = 4;\
                    break;\
            case 32:\
                    i = 5;\
                    break;\
            case 64:\
                    i = 6;\
                    break;\
            case 128:\
                    i = 7;\
                    break;\
            case 256:\
                    i = 8;\
                    break;\
            }\
            i;\
    })
    #define getboxid(i, j) ((3 * ((i) / 3)) + ((j) / 3))
    int rol[9],             //记录横排出现的数字
        col[9],             //记录竖排出现的数字
        box[9],             //记录九各宫出现的数字
        use[9];             //记录横排
    int ans = –1;
    //初始化为-1而不是0 
    int map[9][9];
    int mul[9][9] = {{6, 6, 6, 6, 6, 6, 6, 6, 6},
                     {6, 7, 7, 7, 7, 7, 7, 7, 6},
                     {6, 7, 8, 8, 8, 8, 8, 7, 6},
                     {6, 7, 8, 9, 9, 9, 8, 7, 6},
                     {6, 7, 8, 9,10, 9, 8, 7, 6},
                     {6, 7, 8, 9, 9, 9, 8, 7, 6},
                     {6, 7, 8, 8, 8, 8, 8, 7, 6},
                     {6, 7, 7, 7, 7, 7, 7, 7, 6},
                     {6, 6, 6, 6, 6, 6, 6, 6, 6}};

    void cal(void)
    {
            int i, j;
            int tmp = 0;
            for(i = 0; i < 9; i++){
                    for(j = 0; j < 9; j++){
                            tmp += map[i][j] * mul[i][j];
                    }
            }
            if(tmp > ans){
                    ans = tmp;
            }
    }

    void srch(int i)
    {
            int j, x, y;
            int pos, p;
            if(i == 9){
                    cal();
                    return ;
            }
            x = 511 ^ use[i];
            if(x == 0){
                    srch(i + 1);
                    return;
                    //掉了return  
            }
            y = x & -x;
            use[i] |= y;
            j = getindex(y);
            pos = 511 ^ (rol[i]|col[j]|box[getboxid(i, j)]);
            while(pos > 0){
                    p = pos & -pos;
                    pos ^= p;
                    map[i][j] = getindex(p) + 1;
                    rol[i] |= p;
                    col[j] |= p;
                    box[getboxid(i, j)] |= p;
                    srch(i);
                    rol[i] ^= p;
                    col[j] ^= p;
                    box[getboxid(i, j)] ^= p;
            }
            use[i] ^= y;
    }

    int main(void)
    {
            int i, j;
            int p;
            freopen(“abc.txt”, “r”, stdin);
            for(i = 0; i < 9; i++){
                    for(j = 0; j < 9; j++){
                            scanf(“%d“, &map[i][j]);
                            if(map[i][j] > 0){
                                    use[i] |= 1 << j;
                                    p = 1 << (map[i][j] – 1);
                                    if(((rol[i] & p)) || ((col[j] & p))
                                            || ((box[getboxid(i, j)] & p))){
                                            printf(“-1\n“);
                                            return 0;
                                    }
                                    rol[i] |= p;
                                    col[j] |= p;
                                    box[getboxid(i, j)] |= p;
                            }
                    }
            }
            srch(0);
            printf(“%d\n“, ans);
            return 0;
    }

      后来找了好久才想起来是把这个重要的剪枝去掉了(就是我认为不重要的部分。)
      修改代码如下:
    #include <stdio.h>
    #define getindex(t) ({\
            int i;\
            switch(t){\
            case 1:\
                    i = 0;\
                    break;\
            case 2:\
                    i = 1;\
                    break;\
            case 4:\
                    i = 2;\
                    break;\
            case 8:\
                    i = 3;\
                    break;\
            case 16:\
                    i = 4;\
                    break;\
            case 32:\
                    i = 5;\
                    break;\
            case 64:\
                    i = 6;\
                    break;\
            case 128:\
                    i = 7;\
                    break;\
            case 256:\
                    i = 8;\
                    break;\
            }\
            i;\
    })
    #define getboxid(i, j) ((3 * ((i) / 3)) + ((j) / 3))
    int rol[9],             //记录横排出现的数字
        col[9],             //记录竖排出现的数字
        box[9],             //记录九各宫出现的数字
        use[9];             //记录横排
    int count[9];           //每行值为0的个数
    int hk[9];              //按照这里的顺序进行深搜!! 重要剪枝
    int ans = –1;
    //初始化为-1而不是0 
    int map[9][9];
    int mul[9][9] = {{6, 6, 6, 6, 6, 6, 6, 6, 6},
                     {6, 7, 7, 7, 7, 7, 7, 7, 6},
                     {6, 7, 8, 8, 8, 8, 8, 7, 6},
                     {6, 7, 8, 9, 9, 9, 8, 7, 6},
                     {6, 7, 8, 9,10, 9, 8, 7, 6},
                     {6, 7, 8, 9, 9, 9, 8, 7, 6},
                     {6, 7, 8, 8, 8, 8, 8, 7, 6},
                     {6, 7, 7, 7, 7, 7, 7, 7, 6},
                     {6, 6, 6, 6, 6, 6, 6, 6, 6}};

    void cal(void)
    {
            int i, j;
            int tmp = 0;
            for(i = 0; i < 9; i++){
                    for(j = 0; j < 9; j++){
                            tmp += map[i][j] * mul[i][j];
                    }
            }
            if(tmp > ans){
                    ans = tmp;
            }
    }

    void srch(int t)
    {
            int i, j, x, y;
            int pos, p;
            if(t == 9){
            //这里是t不是i 
                    cal();
                    return ;
            }
            i = hk[t];
            x = 511 ^ use[i];
            if(x == 0){
                    srch(t + 1);
                    return;
                    //掉了return  
            }
            y = x & -x;
            use[i] |= y;
            j = getindex(y);
            pos = 511 ^ (rol[i]|col[j]|box[getboxid(i, j)]);
            while(pos > 0){
                    p = pos & -pos;
                    pos ^= p;
                    map[i][j] = getindex(p) + 1;
                    rol[i] |= p;
                    col[j] |= p;
                    box[getboxid(i, j)] |= p;
                    srch(t);
                    rol[i] ^= p;
                    col[j] ^= p;
                    box[getboxid(i, j)] ^= p;
            }
            use[i] ^= y;
    }

    int main(void)
    {
            int i, j;
            int p;

            for(i = 0; i < 9; i++){
                    for(j = 0; j < 9; j++){
                            scanf(“%d“, &map[i][j]);
                            if(map[i][j] > 0){
                                    use[i] |= 1 << j;
                                    p = 1 << (map[i][j] – 1);
                                    if(((rol[i] & p)) || ((col[j] & p))
                                            || ((box[getboxid(i, j)] & p))){
                                            printf(“-1\n“);
                                            return 0;
                                    }
                                    rol[i] |= p;
                                    col[j] |= p;
                                    box[getboxid(i, j)] |= p;
                            }else{
                                    count[i]++;
                            }
                    }
            }
            for(i = 0; i < 9; i++){
                    hk[i] = i;
            }

            for(i = 1; i < 9; i++){
                    p = hk[i];
                    for(j = i – 1; j >= 0 && count[hk[j]] > count[p]; j–){
                            hk[j + 1] = hk[j];
                    }
                    hk[j + 1] = p;
            }
            srch(0);
            printf(“%d\n“, ans);
            return 0;
    }
  • NOIP2009 Hankson的趣味题 解题报告

    Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson。现在,刚刚放学回家的Hankson 正在思考一个有趣的问题。
    今天在课堂上,老师讲解了如何求两个正整数c1 和c2 的最大公约数和最小公倍数。现在Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a0,a1,b0,b1,设某未知正整数x 满足:
    1. x 和a0 的最大公约数是a1;
    2. x 和b0 的最小公倍数是b1。
    Hankson 的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的x 的个数。请你帮助他编程求解这个问题。

    第一行为一个正整数n,表示有n 组输入数据。接下来的n 行每行一组输入数据,为四个正整数a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入数据保证a0 能被a1 整除,b1 能被b0 整除。
    【数据范围】
    对于 50%的数据,保证有1≤a0,a1,b0,b1≤10000 且n≤100。
    对于 100%的数据,保证有1≤a0,a1,b0,b1≤2,000,000,000 且n≤2000。

    每组输入数据的输出结果占一行,为一个整数。
    对于每组数据:若不存在这样的 x,请输出0;
    【说明】
    第一组输入数据,x 可以是9、18、36、72、144、288,共有6 个。
    第二组输入数据,x 可以是48、1776,共有2 个。
    若存在这样的 x,请输出满足条件的x 的个数;

    ====================================华丽的分割线====================================

    题目如上,我一开始的思路是把所有a1的倍数都枚举一次,然后用b1作为上限。

    但是估计会超时,就没下手,网上查了一下,有人用我这个思路,50分!!!以后我还是有思路就尝试下吧。。
    后来看了另外的思路,任何数都能够表示成素数之和,如:5=5^1,, 6 = 2^13^1,, 8 = 2^3等等。
    然后是最大公倍数=2^min(x1, y1)
    3^min(x2, y2)……
    最小公倍数=2^max(x1, y1)
    3^max(x2, y2)*……
    代码等下写上来.

    代码如下:

    #include <math.h>
    #include <stdio.h>
    #include <string.h>
    #define bzero(a) memset(a, 0, sizeof(a))
    #define MAX 10000
    int prime[MAX], count[MAX], num[MAX];
    int tot, t;
    
    int hcf(int a, int b)
    {
     int t;
     while(b){
     t = b;
     b = a % t;
     a = t;
     }
     return a;
    }
    
    void dfs(int now, int sum)
    {
     int i, n;
     if(now == t){
     num[tot++] = sum;
     return ;
     }
     dfs(now + 1, sum);
     for(i = 0; i < count[now]; i++){
     sum *= prime[now];
     dfs(now + 1, sum);
     }
    }
    
    void work(int n)
    {
     int i = 2;
     int limit = sqrt(n);
     while(i <= limit){
     if(n % i == 0){
     prime[t] = i;
     count[t] = 0;
     do{
     count[t]++;
     n /= i;
     }while(n % i == 0);
     t++;
     limit = sqrt(n);
     }
     i++;
     }
     if(n != 1){
     prime[t] = n;
     count[t++] = 1;
     }
     dfs(0, 1);
    }
    
    int main(void)
    {
     int n;
     int a0, a1, b0, b1;
     int i, j;
     int ans;
     scanf(%d, &n);
     for(i = 0; i < n; i++){
     scanf(%d%d%d%d, &a0, &a1, &b0, &b1);
     bzero(num);
     bzero(count);
     bzero(prime);
     tot = t = 0;
     work(b1);
     ans = 0;
     for(j = 0; j < tot; j++){
     // 这里的变量我用的都是i...+_^
     if((hcf(num[j], a0) == a1) &&
     ((num[j] / hcf(num[j], b0) * b0) == b1)){
     //必须写成上面这样, 而不是 num[j] * b0 / hcf(num[j], b0).
     //找了我两个多小时, 原来是先相乘的话会超过int的范围, 
     //而先除的话就不会超范围了 
     ans++;
     }
     }
     printf(%d\\n, ans);
     }
     return 0;
    }
     忽然想到了剪枝地方法,直接寻找所有与b0的最小公倍数是b1的数字,代码如下:
    #include <math.h>
    #include <stdio.h>
    #include <string.h>
    #define bzero(a) memset(a, 0, sizeof(a))
    #define MAX 10000
    int prime[MAX], count[MAX], num[MAX];
    int tot, t;
    int a0, a1, b0, b1;
    
    int hcf(int a, int b)
    {
     int t;
     while(b){
     t = b;
     b = a % t;
     a = t;
     }
     return a;
    }
    
    void dfs(int now, int sum)
    {
     int i, n, r;
     if(now == t){
     num[tot++] = sum;
     return ;
     }
     n = 0;
     r = prime[now];
     while(b0 % (r) == 0 && n < count[now]){ //剪枝, 使程序更上一层楼
     //这里直接寻找和b0的公约数是b1的数字 
     r *= prime[now];
     n++;
     }
     if(n < count[now]){
     while(n + 1 < count[now]){
     r *= prime[now];
     n++;
     }
     dfs(now + 1, sum * r);
     return ;
     }
    
     dfs(now + 1, sum);
     for(i = 0; i < count[now]; i++){
     sum *= prime[now];
     dfs(now + 1, sum);
     }
    }
    
    void work(int n)
    {
     int i = 2;
     int limit = sqrt(n);
     while(i <= limit){
     if(n % i == 0){
     prime[t] = i;
     count[t] = 0;
     do{
     count[t]++;
     n /= i;
     }while(n % i == 0);
     t++;
     limit = sqrt(n);
     }
     i++;
     }
     if(n != 1){
     prime[t] = n;
     count[t++] = 1;
     }
     dfs(0, 1);
    }
    
    int main(void)
    {
     int n;
     int i, j;
     int ans;
     scanf(%d, &n);
     for(i = 0; i < n; i++){
     scanf(%d%d%d%d, &a0, &a1, &b0, &b1);
     bzero(num);
     bzero(count);
     bzero(prime);
     tot = t = 0;
     work(b1);
     ans = 0;
     for(j = 0; j < tot; j++){
     // 这里的变量我用的都是i...+_^
    /* if((hcf(num[j], a0) == a1) &&
     ((num[j] / hcf(num[j], b0) * b0) == b1)){*/
     //必须写成上面这样, 而不是 num[j] * b0 / hcf(num[j], b0).
     //找了我两个多小时, 原来是先相乘的话会超过int的范围, 
     //而先除的话就不会超范围了
    
     //当程序优化之后上面的判断就变成了下面的判断:
     if(hcf(num[j], a0) == a1){
     ans++;
     }
     }
     printf(%d\\n, ans);
     }
     return 0;
    }

    忽然又想到了一些剪枝,我还尝试一下。

  • NOIP2009 潜伏者 解题报告

    今天把NOIP 2009的所有题目做了一遍,当做考试来做,结果只做出了这一题,而且还只有90分。。死心了。。
    代码如下:

    /*要注意:
     * 1.\'A\'-\'Z\'扫描完毕就停止, (不管内容还有没有~!)
     * 2,长度小于26就Failed
     * 3,二者是一一对应的关系
     * 4,输入的字符串是密子, 不是原信息
     */
    #include <stdio.h>
    **char** map[26], mapp[26];
    **char** string[101];
    **char** start[101], end[101];
    
    **int** main(**void**)
    {
     **int** count = 0;
     **int** i;
     scanf(%s, end); //输入的时候写成了%s\\n,,
     scanf(%s, start);
     scanf(%s, string);
     i = 0;
     **while**(count < 26 && end[i] != \'\\0\'){
     **if**(((map[end[i] - \'A\'] > 0) && (map[end[i] - \'A\'] != start[i])) ||
     ((mapp[start[i] - \'A\'] > 0) && (map[start[i] - \'A\'] != end[i]))){
     //两种数据是一一对应的~! 
     **break**;
     }
     **if**(map[end[i] - \'A\'] == 0){ //忘记给count递增了..
     map[end[i] - \'A\'] = start[i];
     mapp[start[i] - \'A\'] = end[i];
     //两种数据是一一对应的~!
     count++;
     }
     i++; //掉了i++
     //差点提交了, 要把i放在判断的外面才行
     }
     **if**(count != 26){
     printf(Failed\\n);
     **return** 0;
     }
     i = 0; //忘记赋值了
     **while**(string[i] != \'\\0\'){
     putchar(map[string[i] - \'A\']);
     i++; //掉了i++
     }
     putchar(\'\\n\');
     **return** 0;
    }

    顺便提一下,上面的代码是使用Vim转换的!

  • USACO 3.3-1 Riding the Fences骑马修栅栏

    欧拉回路,我知道怎么做,但是我不知到为什么可以这么做!,囧囧;就当是背课文把,反正这就是欧拉回路。
    如果有节点的度为奇数就从它开始,否则就从最小的开始,然后就是看下面的代码把:

     #include <stdio.h>
    #define MAXV 500
    #define MAXE 1024
    char map[MAXV][MAXV];
    int path[MAXE];
    int degree[MAXV];
    int len;
    int max;
    
    void add(int a, int b)
    {
     map[a][b]++, degree[a]++;
    }
    
    void delete(int a, int b)
    {
     map[a][b]--, degree[b]--;
    }
    
    int getneighbor(int a)
    {
     int i;
     for(i = 0; degree[a] != 0; i++){
     if(map[i][a]){
     return i;
     }
     }
    }
    
    void fence(int now)
    {
     int i;
     while(degree[now]){
     i = getneighbor(now);
     delete(i, now);
     delete(now, i);
     fence(i);
     }
     path[len++] = now;
    }
    
    int main(void)
    {
     int i;
     int n, k = 501;
     int a, b;
     freopen(fence.in, r, stdin);
     freopen(fence.out, w, stdout);
     scanf(%d, &n);
     for(i = 0; i < n; i++){
     scanf(%d%d, &a, &b);
     a--, b--;
     add(a, b);
     add(b, a);
     if(max < a){
     max = a;
     }
     if(max < b){
     max = b;
     }
     if(k > a){
     k = a;
     }
     if(k > b){
     k = b;
     }
     }
     for(i = 0; i <= max; i++){
     if(degree[i] & 1){
     k = i;
     break;
     }
     }
     fence(k);
     for(i = len - 1; i >= 0; i--){
     printf(%d\\n, path[i] + 1);
     }
     return 0;
    }