Node.js について
1.1 ローカルサーバーを立ち上げてHTMLファイルをブラウザに表示させる
ローカルのWebサーバーを立ち上げても、そのwebサイトは自身のPC上でしか閲覧できません。これをインターネット上で、外部から閲覧できるようにします。以下の説明は、Node.jsの環境設定を終わらせているものと仮定して話を進めています。以下のコードはブラウザに表示させるhtmlファイルとなります。ファイル名はaaa.htmlです。<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Earth</title> </head> <body> <h2>にゃーん</h2> <div class = "tweet_share"> <font size = "4">ボタンを押して、Twitterでシェアしてみよう!<br></font> <a href="https://twitter.com/share?ref_src=twsrc%5Etfw" class="twitter-share-button" data-size="large" data-show-count="false">Tweet</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </div> <script src = "sarcle.js"></script> </body> </html>
javascriptのコードは以下の通りです。ファイル名はapp.jsです。
const http = require('http'); const hostname = '127.0.0.1'; const port = 3000; var server = http.createServer(); server.on('request', doRequest); // ファイルモジュールを読み込む var fs = require('fs'); // リクエストの処理 function doRequest(req, res) { // ファイルを読み込んだら、コールバック関数を実行する。 fs.readFile('./aaa.html', 'utf-8' , doReard ); // コンテンツを表示する。 function doReard(err, data) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write(data); res.end(); } } server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); });
これらの2つのファイルを同じディレクトリ下において下さい。ファイルを保存したら、ターミナル上でそのディレクトリ下に移動してください。cdコマンドで移動みたいな感じです。
$ node app.js
をターミナルに打ち込みます。私はWindows 10 のwsl2環境で行いました。wslでなくても実行できます。その後以下のように表示されればローカルサーバーの立ち上げに成功です。
ポート番号3000番ですね。その後ブラウザの検索欄で、localhost:3000 と入力して下さい。
すると、上の画像のように、htmlファイルで記述したものがブラウザ上に表示されます。しかし、これはローカル環境でしか反映されません。次に、インターネット上で誰でもこのwebページにアクセスできるようにします。
1.2 ngrokでローカル環境外からでも閲覧可能にする
https://ngrok.com/上のサイトからngrokを任意のディレクトリにインストールして、解凍してください。すると、ngrok.exeという実行ファイルが出現します。それを起動させ、
ngrok http 3000
と打ち込むと外部公開できるようになります。
上の図のForwardingという欄の後に記述されているものが、アクセスできるurlとなります。
Ctrl+C のキーを押すと外部公開終了となり、urlにアクセスできなくなります。ちなみに、このurlは毎回異なる値となります。
2-1 expressでhttpサーバーを作る
この記事が分かりやすかったので参考にしました。blog.katsubemakito.net
以下のコードは、webサイトにアクセスがあった時に、Terminal上でログ出力するというものです。サーバー管理用のserv.jsとブラウザ表示用のaaa.htmlを同じディレクトリ下に置いています。
const express = require("express"); const app = express(); const port = 3000; // ルーティングの設定 app.get("/", (req, res) =>{ res.sendFile(`${__dirname}/aaa.html`); console.log("/ へアクセスがありました"); }); // HTTPサーバを起動する app.listen(port, () => { console.log(`listening at http://localhost:${port}`); });
アクセスカウンタを実装したコードは以下の通り。localhost:3000/resetのurlにアクセスするとアクセスカウンタの数字がリセットされる。
const express = require("express"); const app = express(); const port = 3000; // カウンター用のデータ let COUNT = 1; // ルーティング app.get("/", (req, res)=>{ res.send(`あなたは${COUNT}人目のお客様です`); COUNT++; }); app.get("/reset", (req, res)=>{ res.send(`カウントをリセットしました`); COUNT=1; }); // サーバを起動 app.listen(port, ()=>{ console.log(`Running at http://localhost:${port}/`); })
メッセージ送信フォームを作る
ファイル構成|-document root | app.js | file1.txt |---views index.ejs
クライアント側から入力された情報を、コンソール画面に出力し、file1.txtに追記するというシステムです。非同期処理で実装しているため、高速です。
Body Parser(body-parser)でPOST処理をおこなう[フォーム]
const express = require("express") const ejs = require('ejs') const bodyParser = require("body-parser") const app = express() const fs = require("fs"); var data = "yet"; const port = 3000; app.set('ejs', ejs.renderFile) app.use(bodyParser.urlencoded({ extended: false })) app.get("/", (req, res) => { res.render("./index.ejs", { name: '未送信', message: '未送信' }) }); app.post("/", (req, res) => { res.render('index.ejs', { name: req.body.name, message: req.body.message }) data = req.body.name+"さん : "+req.body.message; fs.appendFile("file1.txt", data+'\n', (err) => { if(err){ console.log(`[error] ${err}`); } console.log(data); }); }); app.listen(port, () => { console.log(`listening at http://localhost:${port}`); });
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <style> .size-input-name {width: 16em; height: 2em;} .size-input-message {width: 50em; height: 3em; } </style> </head> <body> <h2>メッセージ送信フォーム</h2> <br> <form action="/" method="post"> <input type="text" name="name" placeholder="名前" class = "size-input-name"> <hr> <textarea type="text" name = "message" rows = "10" cols = "80" placeholder="メッセージ"></textarea> <hr> <button type="submit" name="button">送信</button> </form> <br> <h2>送信内容</h2> <ul> <li>名前:<%=name %></li> <li>メッセージ:<%=message %></li> </ul> </body> </html>
ABC200-D
#include<bits/stdc++.h> using namespace std; using ll = long long; int main(){ string s; cin >> s; deque<char> dq; ll n = s.size(); ll flag = 1; for(ll i=0; i<n; i++){ if(s[i] == 'R'){ flag*=-1; }else{ if(flag == 1){ if(!dq.empty() && s[i] == dq.back()) dq.pop_back(); else dq.push_back(s[i]); }else{ if(!dq.empty() && s[i] == dq.front()) dq.pop_front(); else dq.push_front(s[i]); } } } string T = ""; for(char x : dq) T+=x; if(flag == -1) reverse(T.begin(), T.end()); cout << T << endl; return 0; }
感想
先頭要素や末尾の要素を削除するために、sutstrやdeleteを使うとo(n)くらいかかるため、時間が間に合わない。デキューは、末尾先頭への要素の追加削除,参照をo(1)で行うため、この問題を解くことに適している。それから、デキューが空の状態で中身を参照すると、配列外参照となるため、以下のようにして対応する。!dq.empy()が偽の時それ以降のs[i] == dq.back()が行われない。逆に左右を逆にすると最初に、dq.back()の参照が行われてしまい、配列外参照のエラーになる恐れがあるため、必ず左側に!dq.empty()を書く必要がある。 if(!dq.empty() && s[i] == dq.back()) dq.pop_back();
Pythonのメモ帳
値の宣言
a=10, b=20を一行で宣言する
a, b = 10, 20
値の交換
例えば、a=2, b=5の入力を与えると、a=5, b=2になる
a, b = map(int, input().split()) a, b = b, a
配列
昇順ソート
a.sort()
a = sorted(a)
降順ソート
a.sort(reverse = True) a = sorted(a, reverse = True)
リスト内包表記
1行目の表記では、if文で真と判定されたもののみが配列に入れられる。
even_numbers = [x for x in range(11) if x%2 == 0] squares = [x*x for x in range(5)] even_squares = [x*x for x in even_numbers] print(even_numbers) print(squares) print(even_squares)
出力
[0, 2, 4, 6, 8, 10] [0, 1, 4, 9, 16] [0, 4, 16, 36, 64, 100]
真偽値
これら8つの値以外は全て真(True)として読みとられる。
if not 0: print("Yes1") if not 0.0: print("Yes2") if not []: print("Yes3") if not {}: print("Yes4") if not "": print("Yes5") if not None: print("Yes6") if not False: print("Yes7") if not set(): print("Yes8")
出力
Yes1 Yes2 Yes3 Yes4 Yes5 Yes6 Yes7 Yes8
例えば文字列"aaaaa"を突っ込むと、真として判定される
if "aaaaa": print("Yes") #Yes
木構造の最短経路問題 ABC-70D Transit Tree Path
問題文
頂点の木が与えられます。木とはグラフの一種であり、頂点の数をとすると、辺の数がN-1本である閉路の無い連結グラフです。
番目の辺は頂点と頂点を距離で結びます。
また、Q個の質問クエリと整数が与えらえます。
番目の質問クエリでは、頂点から頂点を経由しつつ、頂点まで移動する場合の最短経路の距離を求めて下さい。
atcoder.jp
考えたこと
- 頂点から頂点への頂点を経由する場合の最短経路は、頂点からへの最短経路と頂点からへの最短経路の和で求まる。
- 最初ダイクストラ法で実装しようとしたが、よく考えたら、閉路が無い木構造であり、ある頂点からある頂点までの経路が一つしかないため、深さ優先探索(dfs)で探索すれば十分であることが分かった。
- 辺の数がなので、間違えてforループを回すとバグらせるので注意が必要。
const int limit = 100010; using edge = struct{ll to; ll cost;}; vector<edge> tree[limit]; ll depth[limit]; void dfs(ll v, ll p, ll d){ depth[v] = d; for(auto &e : tree[v]){ if(e.to == p) continue; dfs(e.to, v, d+e.cost); } } int main() { ll n; cin >> n; for(ll i=0; i<n-1; i++){ ll a, b, c; cin >> a >> b >> c; tree[a].push_back({b, c}); tree[b].push_back({a, c}); } ll Q, K; cin >> Q >> K; dfs(K, -1, 0); for(ll i=0; i<Q; i++){ ll x, y; cin >> x >> y; cout << depth[x]+depth[y] << '\n'; } return 0; }
蟻本p34 部分和問題 深さ優先探索をNimで解く
問題
整数が与えられます。その中からいくつか選び、その和をちょうどにすることができるか判定しなさい。
入出力
コード
import sequtils, strutils, strformat, algorithm, math, sugar, complex {.warning[UnusedImport]: off.} var n, k: int var a = newseq[int]() proc dfs(i:int, sum:int): bool = if i == n: return sum == k if dfs(i+1, sum): return true if dfs(i+1, sum+a[i]): return true return false n = stdin.readLine.parseInt() a = stdin.readLine.split.map(parseInt) k = stdin.readLine.parseInt() if dfs(0, 0): echo "Yes" else: echo "No"