zoukankan      html  css  js  c++  java
  • 虫食算&燈

    题目描述

    所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:

     43#9865#045
    +  8468#6633
     44445509678

    其中$#$号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是55和33,第二行的数字是55。

    现在,我们对问题做两个限制:

    首先,我们只考虑加法的虫食算。这里的加法是NN进制加法,算式中三个数都有NN位,允许有前导的00。

    其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。如果这个算式是NN进制的,我们就取英文字母表午的前NN个大写字母来表示这个算式中的00到N-1N1这NN个不同的数字:但是这NN个字母并不一定顺序地代表00到N-1N1。输入数据保证NN个字母分别至少出现一次。

     BADC
    +CBDA
     DCCC

    上面的算式是一个4进制的算式。很显然,我们只要让ABCDABCD分别代表01230123,便可以让这个式子成立了。你的任务是,对于给定的NN进制加法算式,求出NN个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解。

    输入输出格式

    输入格式:

    包含四行。
    第一行有一个正整数N(N le 26)N(N26)。

    后面的三行,每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有NN位。

    输出格式:

    一行,即唯一的那组解。

    解是这样表示的:输出NN个数字,分别表示A,B,C,…A,B,C,…所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cmath>
      6 using namespace std;
      7 const int maxn=307;
      8 int a[maxn],b[maxn],c[maxn],num[maxn],n;
      9 bool vis[maxn];
     10 void dfs(int pos,int lft){
     11   //cout<<pos<<" "<<lft<<":"<<endl;
     12   //for(int i=1;i<=n;i++) cout<<num[i]<<" "; cout<<endl;
     13   
     14   
     15   if(pos==n+1&&lft!=0) return;
     16   /*for(int i=pos+1;i<=n;i++){
     17     if(!vis[num[a[pos]]]||!vis[num[b[pos]]]||!vis[num[c[pos]]]) continue;
     18     if((num[a[pos]]+num[b[pos]])%n!=num[c[pos]]) return;
     19   }*/
     20   bool flag=true;
     21   for(int i=1;i<=n;i++) if(num[i]==-1) flag=false;
     22   if(flag){
     23     for(int i=1;i<=n;i++) cout<<num[i]<<" "; cout<<endl; 
     24     exit(0);
     25   }
     26   
     27   
     28   if(num[a[pos]]>=0&&num[b[pos]]>=0&&num[c[pos]]>=0){
     29       //cout<<"a"<<endl;
     30     if((num[a[pos]]+num[b[pos]]+lft)%n!=num[c[pos]]) return;
     31     else dfs(pos+1,(num[a[pos]]+num[b[pos]+lft])/n);
     32   }
     33   
     34   else if(num[a[pos]]>=0&&num[b[pos]]>=0&&num[c[pos]]==-1){
     35       //cout<<"b"<<endl;
     36     num[c[pos]]=(num[a[pos]]+num[b[pos]]+lft)%n;
     37     if(vis[num[c[pos]]]){num[c[pos]]=-1;return;}
     38     vis[num[c[pos]]]=true;
     39     dfs(pos+1,(lft+num[a[pos]]+num[b[pos]])/n);
     40     vis[num[c[pos]]]=false;num[c[pos]]=-1;
     41   }
     42   else if(num[a[pos]]>=0&&num[b[pos]]==-1&&num[c[pos]]>=0){
     43       //cout<<"c"<<endl;
     44     for(int i=0;i<=n-1;i++){
     45       if(vis[i]) continue;
     46       if((num[a[pos]]+i+lft)%n==num[c[pos]]){
     47         num[b[pos]]=i;vis[num[b[pos]]]=true;
     48         dfs(pos+1,(lft+num[a[pos]]+num[b[pos]])/n);
     49         vis[num[b[pos]]]=false;num[b[pos]]=-1;
     50       }
     51     }
     52   }
     53   else if(num[a[pos]]==-1&&num[b[pos]]>=0&&num[c[pos]]>=0){
     54       //cout<<"d"<<endl;
     55     for(int i=0;i<=n-1;i++){
     56       if(vis[i]) continue;
     57       if((i+num[b[pos]]+lft)%n==num[c[pos]]){
     58         num[a[pos]]=i;vis[num[a[pos]]]=true;
     59         dfs(pos+1,(num[a[pos]]+num[b[pos]]+lft)/n);
     60         vis[a[pos]]=false;num[a[pos]]=-1;
     61       }
     62     }
     63   }
     64   
     65   else if(num[a[pos]]==-1&&num[b[pos]]==-1&&num[c[pos]]>=0){
     66       //cout<<"e"<<endl;
     67     for(int i=0;i<=n-1;i++){
     68       if(vis[i]) continue;
     69       for(int j=0;j<=n-1;j++){
     70           if(vis[i]||vis[j]) continue;
     71           if(a[pos]==b[pos]&&i!=j) continue;
     72           if(a[pos]!=b[pos]&&i==j) continue;
     73         if((i+j+lft)%n==num[c[pos]]){
     74           num[a[pos]]=i;num[b[pos]]=j;vis[num[a[pos]]]=true;vis[num[b[pos]]]=true;
     75           dfs(pos+1,(num[a[pos]]+num[b[pos]]+lft)/n);
     76           vis[num[a[pos]]]=false;vis[num[b[pos]]]=false;num[a[pos]]=-1;num[b[pos]]=-1;
     77         }
     78       }
     79     }
     80   }
     81   else if(num[a[pos]]==-1&&num[b[pos]]>=0&&num[c[pos]]==-1){
     82       //cout<<"f"<<endl;
     83     for(int i=0;i<=n-1;i++){
     84       if(vis[i]) continue;
     85       for(int j=0;j<=n-1;j++){
     86           if(vis[i]||vis[j]) continue;
     87           if(a[pos]==c[pos]&&i!=j) continue;
     88           if(a[pos]!=c[pos]&&i==j) continue;
     89         if((i+num[b[pos]]+lft)%n==j){
     90           num[a[pos]]=i;num[c[pos]]=j;vis[num[a[pos]]]=true;vis[num[c[pos]]]=true;
     91           dfs(pos+1,(num[a[pos]]+num[b[pos]]+lft)/n);
     92           vis[num[a[pos]]]=false;vis[num[c[pos]]]=false;num[a[pos]]=-1;num[c[pos]]=-1;
     93         }
     94       } 
     95     }
     96   } 
     97   else if(num[a[pos]]>=0&&num[b[pos]]==-1&&num[c[pos]]==-1){
     98       //cout<<"g"<<endl;
     99     for(int i=0;i<=n-1;i++){
    100       if(vis[i]) continue;
    101       for(int j=0;j<=n-1;j++){
    102           if(vis[i]||vis[j]) continue;
    103           if(b[pos]==c[pos]&&i!=j) continue;
    104           if(b[pos]!=c[pos]&&i==j) continue;
    105         if((num[a[pos]]+i+lft)%n==j){
    106           num[b[pos]]=i;num[c[pos]]=j;vis[num[b[pos]]]=true;vis[num[c[pos]]]=true;
    107           dfs(pos+1,(num[a[pos]]+num[b[pos]]+lft)/n);
    108           vis[num[b[pos]]]=false;vis[num[c[pos]]]=false;num[b[pos]]=-1;num[c[pos]]=-1;
    109         }
    110       }
    111     }
    112   }
    113   
    114   else if(num[a[pos]]==-1&&num[b[pos]]==-1&&num[c[pos]]==-1){
    115       //cout<<"h"<<endl;
    116     for(int i=0;i<=n-1;i++){
    117       if(vis[i]) continue;
    118       for(int j=0;j<=n-1;j++){
    119           if(vis[i]||vis[j]) continue;
    120         for(int k=0;k<=n-1;k++){
    121           if(vis[i]||vis[j]||vis[k]) continue;
    122           if(a[pos]!=b[pos]&&i==j) continue;
    123           if(a[pos]==b[pos]&&i!=j) continue;
    124           if(a[pos]!=c[pos]&&i==k) continue;
    125           if(a[pos]==c[pos]&&i!=k) continue;
    126           if(b[pos]!=c[pos]&&j==k) continue;
    127           if(b[pos]==c[pos]&&j!=k) continue; 
    128           if((i+j+lft)%n==k){
    129             num[a[pos]]=i;num[b[pos]]=j;num[c[pos]]=k;vis[num[a[pos]]]=true;vis[num[b[pos]]]=true;vis[num[c[pos]]]=true;
    130             dfs(pos+1,(num[a[pos]]+num[b[pos]]+lft)/n);
    131             vis[num[a[pos]]]=false;vis[num[b[pos]]]=false;vis[num[c[pos]]]=false;num[a[pos]]=-1;num[b[pos]]=-1;num[c[pos]]=-1;
    132           }
    133         }
    134       }
    135     } 
    136   }
    137 } 
    138 int main(){
    139   freopen("a.in","r",stdin);
    140   cin>>n;
    141   for(int i=n;i>=1;i--){char t;cin>>t;a[i]=t-'A'+1;}
    142   for(int i=n;i>=1;i--){char t;cin>>t;b[i]=t-'A'+1;}
    143   for(int i=n;i>=1;i--){char t;cin>>t;c[i]=t-'A'+1;}
    144   for(int i=1;i<=107;i++) num[i]=-1;
    145   dfs(1,0);
    146 } 

    没有调出来的代码,没法调了TAT

    题解,是把多维的情况转为一维,就是把要求量放入一个数组中,逐个求解

    这样可以降低代码复杂度,更容易接近高分,并且很好想

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 const int maxn=37;
     8 int n,stp;
     9 int a[maxn],b[maxn],c[maxn],num[maxn];
    10 bool vis[maxn],ins[maxn];
    11 int s[maxn];
    12 bool pan(){
    13   for(int i=1;i<=n;i++){
    14     int aa=num[a[i]];int bb=num[b[i]];int cc=num[c[i]];
    15     if(aa==-1||bb==-1||cc==-1) continue;
    16     if((aa+bb)%n!=cc&&(aa+bb+1)%n!=cc) return true;
    17   }
    18   return false;
    19 }
    20 bool check(){
    21   for(int i=1,x=0;i<=n;i++){
    22     int A=num[a[i]],B=num[b[i]],C=num[c[i]];
    23     if(((A+B+x)%n)!=C) return false;
    24     x=(A+B+x)/n;
    25   } 
    26   return true;
    27 }
    28 void dfs(int x){
    29   //cout<<x<<endl;
    30   if(pan()==true) return;
    31     if(x==n+1) {
    32         if(check()==true){
    33           for(int i=1;i<=n;i++) cout<<num[i]<<" "; cout<<endl;
    34           exit(0);
    35         }
    36         return;
    37     }
    38   for(int i=n-1;i>=0;i--)
    39     if(!vis[i]) {
    40       num[s[x]]=i;vis[i]=true;
    41       dfs(x+1);
    42       num[s[x]]=-1;
    43       vis[i]=false;
    44     }
    45   return;
    46 }
    47 int main(){
    48   //freopen("a.in","r",stdin);
    49   cin>>n;
    50   for(int i=0;i<=n;i++) num[i]=-1;
    51   for(int i=n;i>=1;i--){
    52     char t;cin>>t;
    53     a[i]=t-'A'+1;
    54   }
    55   for(int i=n;i>=1;i--){
    56     char t;cin>>t;
    57     b[i]=t-'A'+1;
    58   }
    59   for(int i=n;i>=1;i--){
    60     char t;cin>>t;
    61     c[i]=t-'A'+1;
    62   }
    63   for(int i=1;i<=n;i++){//低位先进 
    64     if(!ins[a[i]]){
    65       ins[a[i]]=true;s[++stp]=a[i];
    66     }
    67     if(!ins[b[i]]){
    68       ins[b[i]]=true;s[++stp]=b[i];
    69     }
    70     if(!ins[c[i]]){
    71       ins[c[i]]=true;s[++stp]=c[i];
    72     }
    73   }
    74   dfs(1);
    75 } 

    这还在燈中有体现

    贝希和她的闺密们在她们的牛棚中玩游戏。但是天不从人愿,突然,牛棚的电源跳闸了,所有的灯都被关闭了。贝希是一个很胆小的女生,在伸手不见拇指的无尽的黑暗中,她感到惊恐,痛苦与绝望。她希望您能够帮帮她,把所有的灯都给重新开起来!她才能继续快乐地跟她的闺密们继续玩游戏! 牛棚中一共有N(1 <= N <= 35)盏灯,编号为1到N。这些灯被置于一个非常複杂的网络之中。有M(1 <= M <= 595)条很神奇的无向边,每条边连接两盏灯。 每盏灯上面都带有一个开关。当按下某一盏灯的开关的时候,这盏灯本身,还有所有有边连向这盏灯的灯的状态都会被改变。状态改变指的是:当一盏灯是开著的时候,这盏灯被关掉;当一盏灯是关著的时候,这盏灯被打开。 问最少要按下多少个开关,才能把所有的灯都给重新打开。 数据保证至少有一种按开关的方案,使得所有的灯都被重新打开。

    这道题如果直接邻接表加边,用一个long long存状态的话,会很复杂

    代码根本调不出来

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 typedef long long ll;
     8 const int maxn=507;
     9 int n,m,num,ans=0x7f7f7f7f;
    10 ll tmp;
    11 int head[maxn];
    12 struct Edge{
    13   int next,to,dis;
    14 }edge[maxn];
    15 void add(int from,int to){
    16   edge[++num].next=head[from];
    17   edge[num].to=to;
    18   head[from]=num;
    19 }
    20 void dfs(int x,int pre,bool flag,int stp){
    21   if(stp>=ans) return;
    22   if(flag==false){
    23       bool all=true;
    24     for(int i=1;i<=n;i++) if(!((tmp>>i)&1)) {all=false;break;}
    25     if(all==true) {
    26       ans=min(ans,stp);
    27       return;
    28     }
    29   }
    30   if(flag==true){
    31     for(int i=head[x];i;i=edge[i].next){
    32       int v=edge[i].to;
    33       tmp^=(1<<v);
    34     }
    35     for(int i=head[x];i;i=edge[i].next){
    36       int v=edge[i].to;if(v==pre) continue;
    37       dfs(v,x,0,stp);dfs(v,x,1,stp+1);
    38     }
    39     for(int i=head[x];i;i=edge[i].next){
    40       int v=edge[i].to;
    41       tmp^=(1<<v);
    42     }
    43   }
    44   else{
    45     for(int i=head[x];i;i=edge[i].next){
    46       int v=edge[i].to;if(v==pre) continue;
    47       dfs(v,x,0,stp);dfs(v,x,1,stp+1);
    48     }
    49   }
    50 }
    51 int main(){
    52   freopen("a.in","r",stdin);
    53   cin>>n>>m;
    54   for(int i=1;i<=m;i++){
    55     int u,v;cin>>u>>v;
    56     add(u,v);add(v,u);
    57   }
    58   for(int i=1;i<=n;i++) {tmp^=(1<<i);dfs(i,0,1,1);tmp^=(1<<i);}
    59   cout<<ans<<endl;
    60   return 0;
    61 }

    但如果把每个灯都设成一个数,

    那么如果两个灯有边连接,就是这个灯的数要加上与它有边连接的灯的数,这样如果这个灯选,那么直接当前状态异或一下这个灯的数,相当于把这些灯都调换了一下

    再将灯从小到大枚举一遍搜索动还是不动

    当然这样的前提是,每个灯最多只会被动一遍,因为动两边相当于没动,

    这个动一遍的问题,颜鸿宇在夏令营的时候讲过

    这也说明,我看到问题,没有有意识的想它的性质

    这个一定要有,之前的区间统计,就没有想到,不可能有 x,a,y,b的情况,如果想到了,那么正解起码要好想一点,还有之前邮票面值设计,搜索的上下界就没有想到,

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<map>
     7 using namespace std;
     8 typedef long long ll;
     9 const int maxn=607;
    10 const int INF=0x7f7f7f7f;
    11 int n,m,num,ans=INF;
    12 ll all, bin[maxn],p[maxn];
    13 bool flag;
    14 map<ll,int>mp;
    15 void dfs(int x,ll tmp,int usd){//直接用x来记录步数,usd记录用了几个 
    16   if(x==num+1){
    17     if(tmp==all) ans=min(ans,usd);
    18     if(!flag){
    19       if(!mp[tmp]||mp[tmp]>usd) mp[tmp]=usd;//更新注意
    20       return; 
    21     } 
    22     if(flag){
    23       if(mp[all-tmp]!=0){
    24         ans=min(ans,usd+mp[all-tmp]);
    25       }
    26       return;
    27     }
    28     return;
    29   }
    30   dfs(x+1,tmp,usd);
    31   dfs(x+1,tmp^p[x],usd+1);//是异或不是+ 
    32 }
    33 int main(){
    34   cin>>n>>m;
    35   bin[1]=1;for(int i=2;i<=n+1;i++) bin[i]=bin[i-1]<<1;
    36   all=bin[n+1]-1;
    37   for(int i=1;i<=m;i++){
    38     int a,b;cin>>a>>b;
    39     p[a]+=bin[b];p[b]+=bin[a];//使代码,思路简化 
    40   }
    41   for(int i=1;i<=n;i++) p[i]+=bin[i];
    42   num=n/2;dfs(1,0,0);
    43   flag=true;
    44   num=n;dfs(n/2+1,0,0);
    45   cout<<ans<<endl;
    46   return 0; 
    47 }

    尼克的任务,邮票面值设计都有这种把最暴力无脑的搜索或者枚举变得简单好写,或者降低了时间复杂度,空间复杂度

    虫食算和燈都有高斯消去元的解法

    一定要完全掌握,但鉴于今天只做了两个题

    先把链接放在这,一定要看啊

    https://www.luogu.org/problemnew/solution/P1092(虫食算)

    http://hzwer.com/4580.html(灯)

    https://www.luogu.org/problemnew/solution/P2962(灯)

  • 相关阅读:
    编译安装mysql5.7.9
    配置阿里云作为yum 源
    python 序列类型
    python 数据类型之list
    python 数据类型之数float
    深度学习与中文短文本分析总结与梳理
    相似度的算法(欧几里德距离和皮尔逊算法)
    人工智能(Machine Learning)—— 机器学习
    python设置redis过期时间
    K-均值聚类(K-means)算法
  • 原文地址:https://www.cnblogs.com/lcan/p/9818474.html
Copyright © 2011-2022 走看看