ABC026_C

※bukaという変数とkouhaiという変数が混ざって大変汚いコード
部下と上司の木を表現してある社員が部下を持たなければ1,
部下を持っていればその部下の中からmax(部下の給料)+min(部下の給料)+1を返す.
メモ化再起風に解いた.

#include <bits/stdc++.h>
using namespace std;
static const int MAX_N = 20;
 
struct Node{
    vector<Node*> kouhai; 
    int kyuuryou;
};
 
Node worker[MAX_N];
 
int solve(Node *p)
{
    /*
        引数(Node*) : 社員
        返り値(int)  : 給料 worker[num].kyuuryou
    */
    if((int)p->kouhai.size()==0){//部下がいなければ
        //給料を1にセットしてから給料1を返す
        p->kyuuryou = 1;
        return 1;
    }else{//部下がいれば
        //部下全員の給料を求めmax(部下の給料)+min(部下の給料)+1を返す
        vector<int> buka_kyuuryou;
        int max_kyuuryou = INT_MIN;
        int min_kyuuryou = INT_MAX;
        for(int i=0;i<(int)p->kouhai.size();i++){
            int tmp = solve(p->kouhai[i]);//部下p->kouhai[i]の給料
            buka_kyuuryou.push_back(tmp);
            max_kyuuryou = max(tmp,max_kyuuryou);
            min_kyuuryou = min(tmp,min_kyuuryou);
        }
        p->kyuuryou = max_kyuuryou+min_kyuuryou+1; 
        return p->kyuuryou;
    }
}
int main()
{
    int n,x;
    cin>>n;
    for(int i=1;i<n;i++){
        cin>>x;
        worker[x-1].kouhai.push_back(&worker[i]);//社員iの先輩は社員x-1 == 社員x-1の後輩は社員i
    }
    solve(&worker[0]);
    int ans = worker[0].kyuuryou;
    cout<<ans<<endl;
    return 0;
}

より簡単な方法
部下が上司より後になるのを利用して後ろから計算していく.

int P[MAX_N];//給料
int minP[MAX_N];//部下の給料の最小値
int maxP[MAX_N];//部下の給料の最大値
int sub[MAX_N];//部下の人数

for(int i=N-1;i>=0;i--){
    if(sub[i].size()==0){//部下が0人ならば
        P[1]=1;//給料は1
        continue;
    }
    //部下がいるならば部下の中で最大+最小+1
    maxP[i] = 0;
    minP[i] = (int)1e9;
    for(int j=0;j<(sub[i].size();j++){
        maxP[i] = max(maxP[i],P[j]);
        minP[i] = min(minP[i],P[j]);
    }
    P[i] = maxP[i] + minP[i];
}

ABC029_C

'a','b','c'から構成できるn文字の文字列を全て挙げる問題.
n=2ならaa,ab,ac,ba,bb,bc,ca,cb,cc

文字が増えていくので文字列と文字列の長さを引数にした関数を作ればよい.

#include <bits/stdc++.h>
using namespace std;
char alphabet[4] = {'a','b','c'};
int n;

void solve(string s,int cnt){
    if(cnt == 0){//作っている文字列の長さがnならば
        cout<<s<<endl;
        return;
    }
    //作っている文字列の長さがn以下ならば
    //'a','b','c'のどれかを挿れる
    for(int i=0;i<3;i++){
        solve(s+alphabet[i],cnt-1);
    }
}
int main()
{
    cin>>n;
    string s = "";
    solve(s,n);
    return 0;
}

ifでreturn文使うよりもelse文を使ったほうが個人的には綺麗だと感じた.

void solve(string s,int cnt){
    if(cnt == 0){//作っている文字列の長さがnならば
        cout<<s<<endl;
    }else{
        for(int i=0;i<3;i++){
            solve(s+alphabet[i],cnt-1);
        }
    }
}

C++ setの要素の検索

setにある要素が含まれているか否かを判定するにはS.find(value)を用いる.
要素が含まれていない場合はS.end()を返す.
よって

if(S.find(x)!=S.end())cout<<"要素あり";
else cout<<"要素なし";

のように判定すればよい.

#include <bits/stdc++.h>
using namespace std;
int main()
{
    set<int> S;
    S.insert(1);
    S.insert(2);
    if(S.find(2) != S.end()){
        cout<<"2あり"<<endl;
    }else{
        cout<<"2なし"<<endl;
    }
    if(S.find(3) != S.end()){
        cout<<"3あり"<<endl;
    }else{
        cout<<"3なし"<<endl;
    }
    return 0;
}


C++マニアック,STL の set の使い方,how to use STL set,標準テンプレートライブラリ,standard template library,コンテナ,container,C++言語講座

レポート表紙

過去のGISTが見れなくなったので再掲

\documentclass[a4j]{jarticle}
\usepackage{color}
\usepackage{listings,jlisting}
\usepackage{ascmac}
\usepackage{url}

%
\lstset{
language={python},
backgroundcolor={\color[gray]{.85}},
basicstyle={\small},
identifierstyle={\small},
commentstyle={\small\ttfamily \color[rgb]{0,0.5,0}},
keywordstyle={\small\bfseries \color[rgb]{1,0,0}},
ndkeywordstyle={\small},
stringstyle={\small\ttfamily \color[rgb]{0,0,1}},
frame={tb},
breaklines=true,
columns=[l]{fullflexible},
%numbers=left,
xrightmargin=0zw,
xleftmargin=3zw,
numberstyle={\scriptsize},
stepnumber=1,
numbersep=1zw,
morecomment=[l]{//}
}

\usepackage[dvipdfmx]{graphicx}
\begin{document}
\begin{titlepage}
  \title{title}
  \author{author}
\maketitle%タイトルを出力
\vspace{8cm}
%\center{name}
\thispagestyle{empty}
\end{titlepage}


\appendix
\begin{thebibliography}{n}
\bibitem{key1}%文献情報
\end{thebibliography}

\end{document}

Emacsの便利なキーバインド

Ctrl+x h ;全範囲選択
Esc-w ;指定範囲コピー

TeX関連コマンド

$platex test.tex
$dvipdfmx test.dvi
$evince test.pdf

umashika5555.hatenablog.com

Project Euler 83 Path sum: four ways

問題を見た時からdijkstra法だと分かっていたが集中してやりたかったので敢えて取っておいた問題

#include <bits/stdc++.h>
using namespace std;
static const int WHITE = 1;
static const int GRAY  = 2;
static const int BLACK = 3;
static const int INF = 1<<21;
static const int MAX_N = 1000;
static const int N = 80;
int d[N][N];
int color[N][N];
int M[N][N];
int sx,sy,gx,gy;
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};

void dijkstra()
{
    int mincost;
    //初期化
    for(int y=0;y<N;y++){
        for(int x=0;x<N;x++){
            color[y][x]=WHITE;
            d[y][x]=INF;
        }
    }
    color[sy][sx]=GRAY;
    d[sy][sx]=M[sy][sx];

    while(true){
        //集合Sに隣接している頂点のうち最もコストの小さい頂点を探す
        mincost=INF;
        int uy=-1,ux=-1;
        for(int y=0;y<N;y++){
            for(int x=0;x<N;x++){
                if(color[y][x]!=BLACK && d[y][x]<mincost){
                    mincost=d[y][x];
                    uy=y;ux=x;
                }
            }
        }
        if(uy==-1 || ux==-1)break;//集合Sの更新が無かったら終了
        color[uy][ux]=BLACK;//その頂点を集合Sに挿れる
        //集合Sに隣接している頂点のd[v]を更新
        for(int i=0;i<4;i++){
            int vy=uy+dy[i],vx=ux+dx[i];
            if(0<=vy && vy<N && 0<=vx && vx<N){
                if(color[vy][vx]!=BLACK){
                    if(d[vy][vx]>d[uy][ux]+M[vy][vx]){
                        d[vy][vx]=d[uy][ux]+M[vy][vx];
                        color[vy][vx]=GRAY;
                    }
                }
            }
        }
    }
}

vector<string> split(const string &s, char delim)
{
    //文字列から文字をkeyにして分割する
    vector<string> elems;
    stringstream ss(s);
    string item;
    while(getline(ss,item,delim)){
        if(!item.empty()){
            elems.push_back(item);
        }
    }
    return elems;
}

int main()
{
    //test.txt からint型二次元配列をinput
    std::ifstream ifs("test.txt");
    std::string str;
    int i=0,j;
    while(getline(ifs,str))
    {
        std::cout<< str << std::endl;
        vector<string> s = split(str,',');
        for(int j=0;j<80;j++){
            M[i][j] = atoi(s[j].c_str());
        }
        i++;
    }
    cout<<"--------------------------"<<endl;
    sx=0,sy=0;
    gx=N-1,gy=N-1;
    dijkstra();
    cout<<d[gy][gx]<<endl;
    return 0;
}

C++でファイルの読み込み
複数行の,で区切られた数値を二次元配列に格納する処理

std::ifstream ifs("test.txt");
std::string str;
int i=0,j;
while(getline(ifs,str))
{
    std::cout<< str << std::endl;
    vector<string> s = split(str,',');
    for(int j=0;j<80;j++){
        M[i][j] = atoi(s[j].c_str());
        }
    i++;
}

ABC020_C

2分探索と単一始点最短経路問題の問題
dijkstra法は二次元配列と頂点の番号を対応させて考えればよい.

#include <bits/stdc++.h>
using namespace std;
/*
    考え方
    1.2文探索でtmp<=tを満たす最大のtmpを見つける
    2.dijkstra法で'#'の移動コストがtmpであるとして'S'->'G'への移動コストの最小値を求める
*/
#define ll long long int 
static const int WHITE = 1;
static const int GRAY  = 2;
static const int BLACK = 3;
static const int MAX_H = 10;
static const int MAX_W = 10;
static const ll MAX_T = 1e9;
static const ll INF   = INT_MAX;
char maze[MAX_H][MAX_W+1];
ll h,w,t;
ll dt[MAX_H][MAX_W];//頂点の始点からの最小距離
ll color[MAX_H][MAX_W];//
ll sx,sy,gx,gy;
ll dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};

void dijkstra(ll tmp)
{
    //次のマスが黒色'#'だったときの移動コストをtmpとしたときのdijkstra法を用いる

    ll mincost;
    //初期化
    for(ll y=0;y<h;y++){
        for(ll x=0;x<w;x++){
            color[y][x] = WHITE;
            dt[y][x] = INF;
        }
    }
    color[sy][sx] = GRAY;
    dt[sy][sx]=0;    

    while(true){
        mincost=INF;
        ll uy=-1;
        ll ux=-1;
        for(ll y=0;y<h;y++){
            for(ll x=0;x<w;x++){
                if(color[y][x]!=BLACK && dt[y][x]<mincost){
                    mincost = dt[y][x];
                    uy=y;ux=x;  
                }
            }
        }
        if(ux==-1 || uy==-1){
            break;
        }
        color[uy][ux]=BLACK;
        for(ll i=0;i<4;i++){
            ll vy = uy+dy[i],vx=ux+dx[i];
            if(0<=vy && vy<h && 0<=vx && vx<w){
                if(color[vy][vx]!=BLACK){
                    ll cost=0;
                    if(maze[vy][vx]=='#')cost+=tmp;
                    else cost+=1;
                    if(dt[vy][vx]>dt[uy][ux]+cost){
                        dt[vy][vx]=dt[uy][ux]+cost;
                        color[vy][vx]=GRAY;
                    }
                }
            }
        }   
    }
}


bool judge(ll tmp)
{
    //tmp<=tであるかを判定
    //次のマスが黒色'#'だったときの移動コストをtmpとしたときのdijkstra法を用いる
    dt[sy][sx] = 0;
    dijkstra(tmp);
    if(dt[gy][gx]<=t)return true;
    else return false;
}

int binarySearch(ll left,ll right)
{
    //二分探索
    if(left+1==right)return left;
    ll mid = (left+right)/2;
    if(judge(mid)){
        return binarySearch(mid,right);
    }else{
        return binarySearch(left,mid);
    }
}

int main(){
    /*
        ios_base::sync_with_stdio(0); cin.tie(0);
        #ifndef ONLINE_JUDGE
        freopen("input.txt","r",stdin);
        freopen("output.txt","w",stdout);
        #endif
    */

    //input
    cin>>h>>w>>t;
    for(int y=0;y<h;y++){
        scanf("%s",maze[y]);//cin>>maze[y];
    }
    //スタート地点とゴール地点を記録
    for(int y=0;y<h;y++){
        for(int x=0;x<w;x++){
            if(maze[y][x]=='S'){
                sx=x;sy=y;
            }
            if(maze[y][x]=='G'){
                gx=x;gy=y;
            }
        }
    }
    int ans = binarySearch(0,MAX_T);
    cout<<ans<<endl;
    return 0;
}

umashika5555.hatenablog.com

単一始点最短経路 dijkstra法

#include <bits/stdc++.h>
using namespace std;
static const int MAX_N = 100; 
static const int WHITE = 0;//未踏
static const int GRAY  = 1;//確定している点と隣接
static const int BLACK = 2;//確定
static const int INF = 1<<21;

int M[MAX_N][MAX_N] = {0};//隣接行列
int d[MAX_N] = {0};//最短経路コスト
int color[MAX_N] = {WHITE};
int n,u,k,c,v;

void dijkstra(int s){
    int mincost;
    //初期化: 全ての頂点uに対してcolor[u]をWHITE, d[u]をINF, d[s]=0, p[s]=-1;
    for(int u=0;u<n;u++){
        color[u] = WHITE;
        d[u] = INF;
    }
    d[s]=0;
    color[0] = GRAY;

    while(true){
        mincost = INF;
        int u = -1;
        for(int i=0;i<n;i++){
            if(color[i]!=BLACK && d[i]<mincost){
                mincost = d[i];
                u = i;
            }
        }
        if(u==-1){
            break;
        }
        color[u]=BLACK;
        
        for(int v=0;v<n;v++){
            if(color[v]!=BLACK && M[u][v]!=INF){
                if(d[v]>d[u]+M[u][v]){
                    d[v]=d[u]+M[u][v];
                    color[v]=GRAY;
                }
            }
        }
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++){//隣接グラフは重みINFの辺に初期化しておく
        for(int j=0;j<n;j++){
            M[i][j] = INF;
        }
    }
    for(int i=0;i<n;i++){//隣接リストから隣接グラフへ書き換える
        cin>>u>>k;
        for(int j=0;j<k;j++){
            cin>>c>>v;
            M[u][c] = M[c][u] = v;
        }
    }
    //始点は0
    dijkstra(0);
    for(int i=0;i<n;i++){
        cout<<i<<" "<<d[i]<<endl;
    }
    return 0;
}

スクレイピング

imgタグのみを抽出する.

# encoding : utf-8
# for python3
import urllib.request
import os.path
import pyquery as pq
import requests
from bs4 import BeautifulSoup
import urllib.request
from urllib.request import Request, urlopen

#def download(url,folderName):
def scraping():
    url = 'http://umashika5555.hatenablog.com/'#まずはurlをぶち込む
    req = Request(url)
    response = urlopen(req)#開け!url
    html = response.read()#htmlを読み込んでぶち込む
    soup = BeautifulSoup(html, "lxml")#ここでBeautifulsoupの出番だぁっ
    #contents = soup.find_all(id = 'contents') #今回抜き出したいタグ
    contents = soup.find_all("img") #今回抜き出したいタグ
    for i,content in enumerate(contents): 
        print(i,end="")
        print('-'*50)
        print(content)
        

			
if __name__ == '__main__':
	scraping() 

こんな感じの結果が得られる.
f:id:umashika5555:20170322025727p:plain



参考
engineer-terminal.com
qiita.com
umashika5555.hatenablog.com

Python3で画像スクレイピング

指定したサイトで画像を一括ダウンロードできる.
備忘録とかそんな感じ — python3.xでweb上の画像を一括ダウンロード

# encoding : utf-8
# for python3
import urllib.request
import os.path
import pyquery as pq
import requests

def download(url, folderName):
    #フォルダが存在していなかった場合は作成する
	if not os.path.exists(folderName):
		print (folderName + "フォルダを作成しました")
		os.mkdir(folderName)
    
	save_path = './'+folderName+'/'
	src= urllib.request.urlopen(url).read() # decodeしない
	query = pq.PyQuery(src)
	
	for img_tag in query('img'):
		img_url = query(img_tag).attr('src')
		print (os.path.basename(img_url)) # 確認用でターミナルに保存ファイル名を出力
		with open (save_path + os.path.basename(img_url), 'wb') as f:
			raw = requests.get(img_url).content
			f.write(raw)#ファイルに画像を書き込む
			
if __name__ == '__main__':
	print ("写真を取得したいサイトのURLを入力")
	input_url = input('>>>  ')
	target_url = input_url
	
	print ("保存先フォルダ名を入力(※存在しない場合は新規作成)")
	input_folderName = input('>>>  ')
	target_folderName = input_folderName
	
	download(target_url, target_folderName)

このブログのURLを指定した場合こんな感じになった.
f:id:umashika5555:20170322025945p:plain
Googleの画像検索のURLだとうまくいかない.

全探索 整数を作れるかの問題

配列の要素から整数を作れるかを判定する関数

#include <bits/stdc++.h>
using namespace std;

static const int MAX_N = 1000;
int n;//配列Aの大きさ
int m;//判定する整数
int A[MAX_N];

bool solve(int i,int m){
    /*
        整数mが作れるか否かの再起関数
    */
    if(m==0)return true;
    if(i>=n)return false;
    return solve(i+1,m) || solve(i+1,m-A[i]);
}

int main()
{
    cin>>n;
    cout<<"判定する整数"<<endl;
    cin>>m;
    for(int i=0;i<n;i++){
        cin>>A[i];
    }
    cout<<(solve(0,m)?"possible":"impossible")<<endl;
    return 0;
}
bool solve(int i,int m){
    /*
        整数mが作れるか否かの再起関数
    */
    if(m==0)return true;
    if(i>=n)return false;
    bool res1 = solve(i+1,m);//A[i]を使わない
    bool res2 = solve(i+1,m-A[i]);//A[i]を使う
    bool res = res1 || res2;
    return res;
}

Ubuntu16.04 でTeXを編集する

qiita.com

1.リポジトリのインストール

sudo apt-add-repository ppa:texlive-backports/ppa

2.TeX Liveインストール

sudo apt-get install texlive-lang-cjk

3.エディタでtest.texを作る

¥documentclass{jarticle}
¥begin{document}
Hello World
¥end{document}

4.コンパイル

platex test.tex
dvipdfmx text.dvi

5.pdfを表示する

evince test.pdf

便利ワザ4

INT_MIN,INT_MAXがint型の最大,最小値の定数らしい.

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int a = INT_MAX;
    int b = INT_MIN;
    cout<<a<<endl;//2147483647
    cout<<b<<endl;//-2147483648
    return 0;
}

その他にも

CHAR_BIT    //char型のビット数
MB_LEN_MAX  //マルチバイト文字の最大バイト数

SCHAR_MIN   //signed char型の最小値
SCHAR_MAX   //signed char型の最大値
UCHAR_MAX   //unsigned char型の最大値
CHAR_MIN    //char型の最小値
CHAR_MAX    //char型の最大値
SHRT_MIN    //short型の最小値
SHRT_MAX    //short型の最大値
USHRT_MAX   //unsigned short型の最大値
INT_MIN     //int型の最小値
INT_MAX     //int型の最大値
UINT_MAX    //unsigned int型の最大値
LONG_MIN    //long型の最小値
LONG_MAX    //long型の最大値
ULONG_MAX   //unsigned long型の最大値

MySQL2

#テーブルの作成
create database sample;

#作成されたテーブルを確認
show databases;

#操作するテーブルを選択
use sample;

#データの型を入力
CREATE TABLE T01Prefecture (
PREF_CD INT(3),
PREF_NAME VARCHAR(10),
PRIMARY KEY (PREF_CD)
);

#中身を見る
select * from to1prefecture;

#データの挿入
insert into to1prefecture(PRED_CD,PREF_NAME) VALUES(1,'hokkaido');
insert into to1prefecture VALUES(2,'aomori');#フィールドを順番通りに全て追加する場合はフィールド名を省略可
insert into to1prefecture(PREF_NAME,PREF_CD) VALUES('iwate',3);
insert into to1prefecture(PRED_CD,PREF_NAME)
VALUES(4,'miyagi'),(5,'aktia'),(6,'yamagata');
insert into to1prefecture set PREF_CD = 7,PREF_NAME='hukushima';#「set」を使う

mysqlweb.net

MySQL1

MySQLの起動

$mysql -u root -p

データベースの表示

SHOW DATABASES;

データベースの作成

CREATE DATABASE SampleDB001;

データベースの選択

USE SampleDB001;

データベースの中身表示

SHOW TABLES;

操作の終了

exit;

クラスタリング

k-means法を用いてクラスタリングを行った.
元画像
f:id:umashika5555:20170318173003j:plain
2色
f:id:umashika5555:20170318173038j:plain
4色
f:id:umashika5555:20170318173053j:plain
8色
f:id:umashika5555:20170318173108j:plain
16色
f:id:umashika5555:20170318173126j:plain
32色
f:id:umashika5555:20170318173148j:plain
64色
f:id:umashika5555:20170318173248j:plain
128色
f:id:umashika5555:20170319215539j:plain
256色
f:id:umashika5555:20170318173338j:plain
1024色
f:id:umashika5555:20170319000449j:plain


1024色までいくとかなり立体感のあるものとなった.
1ピクセルあたり3バイト = (2^8)^3色を表現できるから1024色だからといって元画像に近くは難しい.