---
title : 題解:第一次讀書會
tags : solution
---
# UVa 100 - The 3n+1 problem
- [UVa100 - The 3n+1 problem](https://onlinejudge.org/index.php?option=onlinejudge&Itemid=8&page=show_problem&problem=36)
這題的數字範圍很小,所以還不用太在意會出現超時(TLE)的情形,
用最簡單的邏輯解吧(我個人習慣會把這個東西寫成function):
```cpp=
# include <iostream>
# include <cmath>
using namespace std;
int cycle_len(int n){
int l = 1;
while( n!=1 )
n = (n&1 ? 3*n+1 : n/2), l++;
return l;
}
int main(){
int a,b,max_len;
while(cin>>a>>b){
max_len = 0;
if(a>b) //XOR-swap
a^=b, b^=a, a^=b;
cout<<a<<' '<<b<<' ';
while(a<=b)
max_len = max(cycle_len(a++),max_len);
cout<<max_len<<"\n";
}
}
```
嗯...執行時間有點久呢(310ms),
如果數字範圍很大的話,這個寫法就會炸掉了OAO
**<font color= red>( !!! 以下做法超出目前範圍,看不懂的話沒事的 !!! )</font>**
其實從數字的規律來看,是可以找出一種加速解的。
假設一個n的值是13,將其拿去跑3n+1的迴圈,會得出:
[ 13, 40, 20, 10, 5, 16, 8, 4, 2, 1 ]
套用函式可以得出:
```cpp
cycle_length(13) = 10、
cycle_length(40) = 9、
cycle_length(20) = 8、...
```
其實很多時候,這種3n+1數列是會出現重複元素的,比如說n=22時:
[22, 11, 34, 17, 52, 26, <font color=red>13, 40, 20, 10, 5, 16, 8, 4, 2, 1</font> ]
或是n=32時:[32, <font color=red>16, 8, 4, 2, 1</font>]
如果有方法能夠紀錄已經算過的cycle_length值,
理所當然就可以省去很多步循環操作的步驟。
有一個簡單的作法,用陣列來存!!!!!!
```cpp
cycle_length[13] = 10、
cycle_length[40] = 9、
cycle_length[20] = 8、...
```
(陣列範圍得開得盡量大,好讓循環過程中所產生的n都能被存入陣列)
這種紀錄前面已經計算過的數值的方式,稱之為「<font color=blue>動態規劃(Dynamic Programming)</font>」,
是一種利用記憶體空間換取時間的加速方式
(未來學習演算法與一些難題,都會很常用到這種方式)
以下為本題利用動態規劃加速後的Solution Code:
```cpp=
# include <iostream>
# include <cmath>
using namespace std;
int dp[1000000];
int cycle_len(const int &n) {
if(n<1000000) {
if(dp[n])
return dp[n];
return dp[n] = 1 + cycle_len(n&1 ? 3*n+1 : n/2);
}
return 1 + cycle_len(n&1 ? 3*n+1 : n/2);
}
int main() {
int a,b,max_len;
while(cin>>a>>b) {
cout<<a<<' '<<b<<' ';
max_len = 0;
dp[1] = 1;
if(a>b) //XOR-swap
a^=b, b^=a, a^=b;
while(a<=b)
max_len = max(cycle_len(a++),max_len);
cout<<max_len<<"\n";
}
}
```
(時間複雜度為O(n),I/O加速後,其程式碼耗時為0ms)
---
# ZJ e800 - 影片推薦
- [e800 - 影片推薦](https://zerojudge.tw/ShowProblem?problemid=e800)
用struct下去寫,可以在讀取的時候就用float讀取,
(注意:小於2的24次方純整數在存到float的時候並不會出現精準度的問題)
記得存優先度的時候要用float,
比較麻煩的部分是在sort,可以選擇用泡沫排序法來排序
(推薦可以嘗試把sort寫成一個函式)
我想你們應該都已經聽說了(?),在algorithm裡面有個sort的函式可以用,
但是sort只能排單一變數......嗎?
以下定義一個cmp函式,可以自訂比較數據方式的寫法:
```cpp=
# include <iostream>
# include <string>
# include <algorithm>
using namespace std;
struct Film {
string name;
float prior;
};
bool cmp(Film a, Film b) {
return a.prior > b.prior;
}
int main() {
int N,n;
float p,l,w,r;
Film f[50];
cin>>N;
for(n = 0 ; n<N ; n++) {
cin>>f[n].name>>p>>l>>w>>r;
f[n].prior = p*w/l*r;
}
sort(f,f+N,cmp);
for(n = 0 ; n<N ; n++)
cout<<f[n].name<<"\n";
}
```
---
# ZJ e799 - 資工系的浪漫
- [e799 - 資工系的浪漫](https://zerojudge.tw/ShowProblem?problemid=e799)
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
while (cin >> n >> m){
char c; cin >> c;
while (n--){
long long int num; cin >> num;
string s="";
for (int i=0;i<m;i++){
if (num%2)s+='1';
else s+='0';
num/=2;
}
//cout << s << endl;
for(int i=m-1;i>=0;i--){
if (s[i] == '1') cout << c << " ";
else cout << ". ";
}
cout << "\n";
}
}
}
```
```cpp=
#include<iostream>
using namespace std;
int main(){
int N,M;
long long int i,a;
char c;
cin>>N>>M>>c;
while(N--){
cin>>i;
a = (long long int)1<<(M-1);
if(i>=a)
cout<<c, i-=a;
else
cout<<".";
while(a>>=1){
if(i>=a)
cout<<" "<<c, i-=a;
else
cout<<" .";
}
cout<<"\n";
}
}
```
Python version:
```python=
import sys
for l in [input()]:
n,m=list(map(int, l.replace('\n','').split(' ')))
c=str(input())
for j in range(n):
num=int(input().replace('\n',''))
s=''
for i in range(m):
if num%2: s+='1'
else: s+='0'
num//=2
#print(s)
for i in range(m-1,-1,-1):
if s[i]=='1': print(c,end=' ')
else: print('.',end=' ')
print()
```
---
# UVa 272 - TEX Quotes
- [UVa 272 - TEX Quotes](https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=4&page=show_problem&problem=208)
這一題其實並不需要過多的花招,
用純C的語法下去寫是最好寫的,
在抓入一個字元,判斷是不是雙引號,
再判斷現在的狀態是第一個雙引號還是第二個雙引號就好
(切換狀態的方式可以用XOR就好,就不需要用條件判斷之類的了)
```cpp=
# include <stdio.h>
int main(){
char c;
bool first = true;
while( ( c = getchar() ) != EOF ){
if(c == '\"') {
putchar(first ? '`' : '\'');
putchar(first ? '`' : '\''); // do twice
first ^= true; // switch mode
}
else
putchar(c);
}
}
```
###### posted date: