虫食算&燈

题目描述

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

 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(灯)

猜你喜欢

转载自www.cnblogs.com/lcan/p/9818474.html