1. 程式人生 > >蟲食算&燈

蟲食算&燈

題目描述

所謂蟲食算,就是原先的算式中有一部分被蟲子啃掉了,需要我們根據剩下的數字來判定被啃掉的字母。來看一個簡單的例子:

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