zoukankan      html  css  js  c++  java
  • 第一次训练 密码:acmore

      1 #include <cstdio>
      2 #include <cstring>
      3 #define M 100010
      4 #define INF 0x7FFFFFFF
      5 #define Min(a,b) (a < b ? a : b)
      6 #define mem0(f) memset(f,0,sizeof(f))
      7 char a[6][6];
      8 char b[6][6];
      9 int num[6][6];
     10 
     11 int get_num(int a,int b,int c,int d)
     12 {
     13     int number = 0;
     14     for(int i = 1; i <= 4; i++)
     15     {
     16         if((a & 1 << (i - 1)) == 0)    //位运算,1<<(i-1)=(i-1)*2
     17         {
     18             number++;
     19             num[1][i]++;
     20             num[1][i - 1]++;
     21             num[1][i + 1]++;
     22             num[2][i]++;
     23         }
     24         if((b & 1 << (i - 1)) == 0)
     25         {
     26             number++;
     27             num[2][i]++;
     28             num[2][i - 1]++;
     29             num[2][i + 1]++;
     30             num[1][i]++;
     31             num[3][i]++;
     32         }
     33         if((c & 1 << (i - 1)) == 0)
     34         {
     35             number++;
     36             num[3][i]++;
     37             num[3][i - 1]++;
     38             num[3][i + 1]++;
     39             num[2][i]++;
     40             num[4][i]++;
     41         }
     42         if((d & 1 << (i - 1)) == 0)
     43         {
     44             number++;
     45             num[4][i]++;
     46             num[3][i]++;
     47             num[4][i + 1]++;
     48             num[4][i - 1]++;
     49         }
     50     }
     51     return number;
     52 }
     53 
     54 void flip()
     55 {
     56     for(int i = 1; i <= 4; i++)
     57         for(int j = 1; j <= 4; j++)
     58             if(num[i][j] % 2 != 0)
     59             {
     60                 if(b[i][j] == 'w')
     61                     b[i][j] = 'b';
     62                 else
     63                     b[i][j] = 'w';
     64             }
     65 }
     66 
     67 int checkb()
     68 {
     69     int flag1 = 0;
     70     int flag2 = 0;
     71     for(int i = 1; i <= 4; i++)
     72         for(int j = 1; j <= 4; j++)
     73             if(b[i][j] == 'w')
     74                 return 0;
     75     return 1;
     76 }
     77 
     78 int checkw()
     79 {
     80     int flag1 = 0;
     81     int flag2 = 0;
     82     for(int i = 1; i <= 4; i++)
     83         for(int j = 1; j <= 4; j++)
     84             if(b[i][j] == 'b')
     85                 return 0;
     86     return 1;
     87 }
     88 
     89 int main()
     90 {
     91     int ans = INF;
     92     for(int i = 1; i <= 4; i++)
     93         scanf("%s",a[i] + 1);
     94     for(int i = 0; i < 16; i++)
     95         for(int j = 0; j < 16; j++)
     96             for(int k = 0; k < 16; k++)
     97                for(int p = 0; p < 16; p++)
     98                 {
     99                     memcpy(b,a,sizeof(a));
    100                     mem0(num);
    101                     int number = get_num(i,j,k,p);
    102                     flip();
    103                     if(checkb() || checkw())
    104                         ans = Min(ans,number);
    105                 }
    106     if(ans == INF)
    107         printf("Impossible
    ");
    108     else
    109     printf("%d
    ",ans);
    110     return 0;
    111 }

    网址:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=26732#overview

    先讲一下整体情况,A,B题是差不多的题型,DFS,A题枚举也行一共2^16种可能。

    C题没什么好说的,暴力求解。

    D题,待我再研究下题目。

    E题,貌似数据有问题.....

    F题,本来用母函数做,结果一句:Your program should be able to handle up to 100 coins.差点秒杀全场,结果证明可以用暴力求解,另DP。

    总的一句:暴力专场!!!!!!

    A题,4X4的黑白翻转棋,输出最小的能全变成一种颜色的步数,不能则输出:impossible。

    #include<stdio.h>
    #include<iostream>
    using namespace std;
    int chess[4][4];
    int c=33;
    void build()//将棋盘的颜色以标记化
    {
        char c;
        int i,j;
        for(i=0;i<4;i++)
        for(j=0;j<4;j++)
        {
            cin>>c;
            if(c=='w')
            chess[i][j]=0;
            else
            chess[i][j]=1;
        }
    }
    void turn(int x,int y)//翻转
    {
         if(x>=0&&x<=3&&y>=0&&y<=3)
         chess[x][y]=!chess[x][y];
    }
    void flip(int s)//一个棋子变化,周围四个都要变化
    {
        int i=s/4;//
        int j=s%4;//
        turn(i,j);
        turn(i+1,j);
        turn(i,j+1);
        turn(i-1,j);
        turn(i,j-1);
    }
    int complete()//判断棋盘是否变成同一的颜色
    {
        int i,j,s1=0;
        for(i=0;i<4;i++)
           for(j=0;j<4;j++)
              s1+=chess[i][j];
        if(s1%16)
          return 0;
        else
          return 1;
    }
    void dfs(int s,int b)//进行深搜.s代表当前的方格,b代表翻转的方格数
    {
         if(complete())//如果是同一颜色
         {
             if(c>b)
               c=b;
            return;
         }
         if(s>=16)//如果遍历完
            return;
        dfs(s+1,b);  //不是很理解这一步及以下3步
          flip(s);
        dfs(s+1,b+1);
        flip(s);
    }
    int main()
    {
        build();//将棋盘的颜色以标记化
        dfs(0,0);
        if(c==33)//由于翻转次数最多为4*4*2=32次
          printf("Impossible
    ");
        else
          printf("%d
    ",c);
        return 0;
    }

    上面这种方法待我看过DFS再来看,再做标注。
    另一种代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    int map[4][4],step,flag=0;
    
    void turn(int i,int j)//转换
    {
        map[i][j]=!map[i][j];
        if(i>0)
            map[i-1][j]=!map[i-1][j];
        if(i<3)
            map[i+1][j]=!map[i+1][j];
        if(j>0)
            map[i][j-1]=!map[i][j-1];
        if(j<3)
            map[i][j+1]=!map[i][j+1];
    }
    
    int range()//判定表格是否全部一样
    {
        int i,j;
        for(i=0;i<4;i++)
            for(j=0;j<4;j++)
                if(map[i][j]!=map[0][0])
                    return 0;
        return 1;
    }
    
    int DFS(int i,int j,int dp)//深搜
    {
        if(dp==step)
        {
            flag=range();
            return 0;
        }
        if(flag||i==4)  return 1;
        turn(i,j);
        if(j<3)   
            DFS(i,j+1,dp+1);
        else 
            DFS(i+1,0,dp+1);
        turn(i,j);
        if(j<3)
            DFS(i,j+1,dp);
        else 
            DFS(i+1,0,dp);
        return 0;
    }
    int main()
    {
        int i,j;
        char a;
        for(i=0;i<4;i++)
        {
            for(j=0;j<4;j++)
            {
                scanf("%c",&a);
                if(a=='b')
                    map[i][j]=0;
                else 
                    map[i][j]=1;
            }
            getchar();
        }
        for(step=0;step<=16;step++)
        {
            flag=0;
            DFS(0,0,0);
            if(flag)   break;
        }
        if(flag)
            printf("%d
    ",step);
        else 
            printf("Impossible
    ");
        return 0;
    }

    等我看了DFS再来写。。。。Orz

    另一种,用枚举+位运算:

    /*
    解题思路:
    由于输入的字符串中只含'b'或'w',而且只有16个字符,所以可以将输入的字符串理解为二进制表达式;
    将这个字符串转换成一个10进制数字。然后bfs的同时,再用位运算(^)来改变它周围的数字(字符)。
    具体见程序:
    */
    #include <stdio.h>
    #include <queue>
    #include <string.h>
    #include <stdlib.h>
    #include <algorithm>
    using namespace std;
    struct node
    {
        int step;
        int val;
    };
    int st,used[100000];
    int bfs()
    {
        int i;
        queue<node> q;
        node tmp;
        tmp.step=0;
        tmp.val=st;
        q.push(tmp);
        memset(used,0,sizeof(used));
        used[st]=1;
        while(!q.empty())
        {
            node cur=q.front();
            q.pop();
            if(cur.val==0||cur.val==(1<<16)-1)
                return cur.step;
            for(i=0;i<16;i++)
            {
                node next=cur;
                int tx=i/4,ty=i%4;
                //下面的4个if就是用来判断是否越界,如果没有,那么改变该节点(中心节点的邻节点);
                if(tx-1>=0) next.val^=1<<(15-(4*(tx-1)+ty));
                if(tx+1<4) next.val^=1<<(15-(4*(tx+1)+ty));
                if(ty-1>=0) next.val^=1<<(15-(4*tx+ty-1));
                if(ty+1<4) next.val^=1<<(15-(4*tx+ty+1));
                next.val^=1<<(15-i);
                if(!used[next.val])
                {
                    next.step++;
                    used[next.val]=1;
                    q.push(next);
                }
            }
        }
        return -1;
    }
    int main()
    {
        int i;
        char s[20];
        while(scanf("%s",s)!=EOF)
        {
            st=0;
            for(i=1;i<4;i++) scanf("%s",s+4*i);
            //将输入的字符串转换成一个10进制数。
            for(i=0;i<16;i++)
            {
                st<<=1;
                st|=(s[i]=='b');
            }
            int ans=bfs();
            if(ans==-1) printf("Impossible
    ");
            else printf("%d
    ",ans);
        }
        return 0;
    }

     枚举+位运算:这个比较好理解  1 #include <cstdio>

      2 #include <cstring>
      3 #define M 100010
      4 #define INF 0x7FFFFFFF
      5 #define Min(a,b) (a < b ? a : b)
      6 #define mem0(f) memset(f,0,sizeof(f))
      7 char a[6][6];
      8 char b[6][6];
      9 int num[6][6];
     10 
     11 int get_num(int a,int b,int c,int d)
     12 {
     13     int number = 0;
     14     for(int i = 1; i <= 4; i++)
     15     {
     16         if((a & 1 << (i - 1)) == 0)    //位运算,1<<(i-1)=1*2^(i-1)
     17         {
     18             number++;
     19             num[1][i]++;
     20             num[1][i - 1]++;
     21             num[1][i + 1]++;
     22             num[2][i]++;
     23         }
     24         if((b & 1 << (i - 1)) == 0)
     25         {
     26             number++;
     27             num[2][i]++;
     28             num[2][i - 1]++;
     29             num[2][i + 1]++;
     30             num[1][i]++;
     31             num[3][i]++;
     32         }
     33         if((c & 1 << (i - 1)) == 0)
     34         {
     35             number++;
     36             num[3][i]++;
     37             num[3][i - 1]++;
     38             num[3][i + 1]++;
     39             num[2][i]++;
     40             num[4][i]++;
     41         }
     42         if((d & 1 << (i - 1)) == 0)
     43         {
     44             number++;
     45             num[4][i]++;
     46             num[3][i]++;
     47             num[4][i + 1]++;
     48             num[4][i - 1]++;
     49         }
     50     }
     51     return number;
     52 }
     53 
     54 void flip()
     55 {
     56     for(int i = 1; i <= 4; i++)
     57         for(int j = 1; j <= 4; j++)
     58             if(num[i][j] % 2 != 0)
     59             {
     60                 if(b[i][j] == 'w')
     61                     b[i][j] = 'b';
     62                 else
     63                     b[i][j] = 'w';
     64             }
     65 }
     66 
     67 int checkb()
     68 { 71     for(int i = 1; i <= 4; i++)
     72         for(int j = 1; j <= 4; j++)
     73             if(b[i][j] == 'w')
     74                 return 0;
     75     return 1;
     76 }
     77 
     78 int checkw()
     79 { 82     for(int i = 1; i <= 4; i++)
     83         for(int j = 1; j <= 4; j++)
     84             if(b[i][j] == 'b')
     85                 return 0;
     86     return 1;
     87 }
     88 
     89 int main()
     90 {
     91     int ans = INF;
     92     for(int i = 1; i <= 4; i++)
     93         scanf("%s",a[i] + 1);
     94     for(int i = 0; i < 16; i++)
     95         for(int j = 0; j < 16; j++)
     96             for(int k = 0; k < 16; k++)
     97                for(int p = 0; p < 16; p++)
     98                 {
     99                     memcpy(b,a,sizeof(a));
    100                     mem0(num);
    101                     int number = get_num(i,j,k,p);
    102                     flip();
    103                     if(checkb() || checkw())
    104                         ans = Min(ans,number);
    105                 }
    106     if(ans == INF)
    107         printf("Impossible
    ");
    108     else
    109     printf("%d
    ",ans);
    110     return 0;
    111 }

    B题和A题很像

    大神的代码:

    /*
    
    参考高手的高效解法:
    > 证明:要使一个为'+'的符号变为'-',必须其相应的行和列的操作数为奇数;可以证明,如果'+'位置对应的行和列上每一个位置都进行一次操作,则整个图只有这一'+'位置的符号改变,其余都不会改变.
    > 设置一个4*4的整型数组,初值为零,用于记录每个点的操作数,那么在每个'+'上的行和列的的位置都加1,得到结果模2(因为一个点进行偶数次操作的效果和没进行操作一样,这就是楼上说的取反的原理),然后计算整型数组中一的
    > 个数即为操作数,一的位置为要操作的位置(其他原来操作数为偶数的因为操作并不发生效果,因此不进行操作)
    *********************************
    此上证其可以按以上步骤使数组中值都为‘-’
    ********************************
    在上述证明中将所有的行和列的位置都加1后,在将其模2之前,对给定的数组状态,将所有的位置操作其所存的操作数个次数,举例,如果a[i][j]==n,则对(i,j)操作n次,当所有的操作完后,即全为‘-’的数组。
    其实就是不模2的操作,作了许多的无用功。
    以上的操作次序对结果无影响,如果存在一个最小的步骤,则此步骤一定在以上操作之中。(简单说下:因为以上操作已经包含了所有可改变欲改变位置的操作了)
    而模2后的操作是去掉了所有无用功之后的操作,此操作同样包含最小步骤。
    但模2后的操作去掉任何一个或几个步骤后,都不可能再得到全为‘-’的。(此同样可证明:因为操作次序无影响,先进行最小步骤,得到全为‘-’,如果还剩下m步,则在全为‘-’的数组状态下进行这m步操作后还得到一个全为
    ‘-’的数组状态,此只能是在同一个位置进行偶数次操作,与前文模2后矛盾,所以m=0),因此模2后的操作即为最小步骤的操作。
    */
    #include <iostream>
    using namespace std;
    
    bool mark[4][4];
    char s[4][4];
    
    int main()
    {
        int i,j,k;
        int ci[16],cj[16];
        int nas = 0;
        memset(mark,0,sizeof(mark));
        for(i = 0;i < 4;i++)
            cin >> s[i];
        for(i = 0;i < 4;i++)
            for(j = 0;j < 4;j++)
            {
                char c = s[i][j];
                if(c == '+')
                {
                    mark[i][j] = !mark[i][j];
                    for(k = 0;k < 4;k++)
                    {
                        mark[i][k] = !mark[i][k];
                        mark[k][j] = !mark[k][j];
                    }
                }
    
            }
        for(i = 0;i < 4;i++)
            for(j = 0;j < 4;j++)
                if(mark[i][j] == true)
                {
                    ci[nas] = i + 1;
                    cj[nas] = j + 1;
                    nas ++;
                }
        printf("%d
    ",nas);
        for(i = 0;i < nas;i++)
        {
            printf("%d %d
    ",ci[i],cj[i]);
        }
        return 0;
    }

    这个懂了,NB,在输入+-的时候略坑,上面的s[i]是一次输入一行,就不存在把回车当做一个字符了。时间为  94MS

    这样输入更好:时间为32MS

    for(i=0;i<3;i++)
            for(j=0;j<=4;j++)
             scanf("%c",&map2[i][j]);
        for(j=0;j<4;j++)
            scanf("%c",&map2[3][j]);
    我的代码~~~我是取2的余数决定有没有翻:
     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<string.h>
     4 using namespace std;
     5 int main()
     6 {
     7     int map[4][4],i,j,sum=0,k;
     8     char map2[4][4];
     9     memset(map,0,sizeof(map));
    10     for(i=0;i<3;i++)
    11         for(j=0;j<=4;j++)
    12          scanf("%c",&map2[i][j]);
    13     for(j=0;j<4;j++)
    14         scanf("%c",&map2[3][j]);
    15     getchar();
    16     for(i=0;i<4;i++)
    17         for(j=0;j<4;j++)
    18         {
    19             char c=map2[i][j];
    20             if(c=='+')
    21             {
    22               map[i][j]++;
    23                 for(k=0;k<4;k++)
    24                 {
    25                     map[i][k]++;
    26                     map[k][j]++;
    27                 }
    28             }
    29         }
    30     for(i=0;i<4;i++)
    31         for(j=0;j<4;j++)
    32             if(map[i][j]%2==1)
    33                 sum++;
    34     printf("%d
    ",sum);
    35     for(i=0;i<4;i++)
    36         for(j=0;j<4;j++)
    37             if(map[i][j]%2==1)
    38                 printf("%d %d
    ",i+1,j+1);
    39     return 0;
    40 }
    View Code
    C题.....:
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    int main()
    {
        int n,i,a[500],b[500],maxn,map[100][100],j,k,q;
        while(~scanf("%d",&n)&&n)
        {
            memset(map,0,sizeof(map));
            int x,y,x1,y1;
            maxn=0;
            scanf("%d%d",&x,&y);
            for(i=0;i<n;i++)
            {
                scanf("%d%d",&a[i],&b[i]);
                map[a[i]][b[i]]=1;
            }
            scanf("%d%d",&x1,&y1);
            for(i=1;i<=x-x1+1;i++)
                for(j=1;j<=y-y1+1;j++)
                {
                    q=0;
                    for(k=0;k<n;k++)
                       if(a[k]>=i&&a[k]<i+x1&&b[k]>=j&&b[k]<j+y1&&map[a[k]][b[k]]==1)
                          q++;
                    if(q>maxn)
                        maxn=q;
                }
            printf("%d
    ",maxn);
        }
        return 0;
    }

    建立一个地图,有树的地方标记为1。再暴力就行了。

    D题:表示还是不知道方法,但是要注意double 会失精度。

    大神代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include<math.h>
    int main()
    {
        double a, b, c, A, B, C;
        int N, s, xo, yo, zo, X, Y, Z,XO,YO,ZO, re, sum;
        scanf("%d", &N);
        while(N--)
        {
            scanf("%d%lf%lf%lf", &s, &a,&b,&c);
            sum=s;
            A=b*c;
            B=a*c;
            C=a*b;
            xo=floor(s*A/(A+B+C));
            yo=floor(s*B/(A+B+C));
            zo=floor(s*C/(A+B+C));
            XO=xo-2>0?xo-2:0;
            YO=yo-2>0?yo-2:0;
            ZO=zo-2>0?zo-2:0;
            for(X=XO; X<=xo+2; X++)
            {
                for(Y=YO; Y<=yo+2; Y++)
                {
                    for(Z=ZO;Z<=zo+2&&X+Y+Z<=s; Z++)
                    {
                        re=floor(X*a);
                        if(floor(Y*b)<re)
                            re=floor(Y*b);
                        if(floor(Z*c)<re)
                            re=floor(Z*c);
                        re+=(s-X-Y-Z);
                        if(re>sum)
                            sum=re;
                    }
                }
            }
            printf("%d
    ", sum);
        }
        return 0;
    }

    真心不知道他是怎么分配的。。。

     另一种方法,注意精度。

     1 #include <algorithm>
     2 #include <stdio.h>
     3 #include<string.h>
     4 #define Max(a,b) (a > b ? a : b)
     5 int num[4];
     6 int main()
     7 {
     8     int n;
     9     int bb,bbb,cc,ccc,dd,ddd;
    10     int d,b,c;
    11     int a;
    12     scanf("%d",&n);
    13     while(n--)
    14     {
    15         memset(num,0,sizeof(num));
    16         scanf("%d%d.%d%d.%d%d.%d",&a,&bb,&bbb,&cc,&ccc,&dd,&ddd);
    17         b = (bb * 100 + bbb);
    18         c = (cc * 100 + ccc);
    19         d = (dd * 100 + ddd);
    20         int ans = a;
    21         for(int i=1;i<=a;i++)
    22         {
    23             if((num[1])*b<=(num[2])*c&&(num[1])*b<= (num[3])*d)   //一块钱一块钱放,放在收益最小的栏里
    24                 num[1]++;
    25             else if((num[2])*c<=(num[1])*b&&(num[2])*c<=(num[3])*d)
    26                 num[2]++;
    27             else  if((num[3])*d<=(num[2])*c&&(num[3])*d<=(num[1])* b)
    28                  num[3]++;
    29             if((num[1])*b<=(num[2])*c&&(num[1])*b<=(num[3])*d)
    30                 ans= Max(ans,(num[1]*b)/100+(a-i));
    31             else if((num[2])*c<=(num[1])*b&&(num[2])*c<=(num[3])*d)
    32                 ans= Max(ans,(num[2]*c)/100+(a-i));
    33             else  if((num[3])*d<=(num[2])*c&&(num[3])*d<=(num[1])*b)
    34                 ans= Max(ans,(num[3]*d)/100+(a-i));     //最后和本金相比,取最大值
    35         }
    36         printf("%d
    ",ans);
    37     }
    38     return 0;
    39 }
    View Code

    F:

     1 #include <stdio.h>
     2 int main()
     3 {
     4    int a,b,c,d,e,num,n;
     5    while(~scanf("%d",&n))
     6    {
     7        num=0;
     8    for(a=0;a<=n;a++)
     9     for(b=0;b*5<=n-a;b++)
    10     for(c=0;c*10<=n-a-5*b;c++)
    11     for(d=0;d*25<=n-a-5*b-10*c;d++)
    12      {
    13          e=n-a-5*b-10*c-25*d;
    14          if(e%50==0&&a+b+c+d+e/50<=100)
    15          num++;
    16      }
    17     printf("%d
    ",num);
    18    }
    19    return 0;
    20 }
    View Code

    暴力也能过= =:109ms

  • 相关阅读:
    WPF中调用资源字典的方法
    DataGridView控制单元格修改的输入规则
    将dataGridView数据转成DataTable
    窗体打开后设置某个控件为默认的焦点
    自定义控件属性英文类别
    VMWare虚拟机与主机建立共享文件夹
    与.Net大师Jeffrey Richter面对面交流——TUP对话大师系列活动回顾(多图配详细文字)
    一个编程小题目引发的思考(下)
    一个Quicksort究竟可以写到多么短
    我是如何设计并实现一门程序设计语言——一门函数式编程语言Lucida的诞生
  • 原文地址:https://www.cnblogs.com/riddle/p/3203415.html
Copyright © 2011-2022 走看看