Upgrade to Pro — share decks privately, control downloads, hide ads and more …

NPCA合宿きょーぷろ講義

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for snuke snuke
August 22, 2013

 NPCA合宿きょーぷろ講義

Avatar for snuke

snuke

August 22, 2013
Tweet

More Decks by snuke

Other Decks in Programming

Transcript

  1. 例 N = 4 a = {1,4,3,3} X = 10

    → 4 + 3 + 3 = 10 できる!
  2. 例 N = 4 a = {1,4,3,3} X = 7

    → 1 + 3 + 3 = 4 + 3 = 7 できる!
  3. 目標 o x x x x x x x x

    x o o x x x x x x x x o o x o o x x x x x o o x o o o x o o x o o x o o o o o o x 0 1 2 3 0 1 2 i j 3 4 4 5 6 7 8 9 a = {1 4 3 3}
  4. まずは初期化 o x x x x x x x x

    x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x 0 1 2 3 0 1 2 i j 3 4 4 5 6 7 8 9
  5. a1 = 1 足す/足さないの二択 o x x x x x

    x x x x o o x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x 0 1 2 3 0 1 2 i j 3 4 4 5 6 7 8 9
  6. a2 = 4 o x x x x x x

    x x x o o x x x x x x x x o o x x o o x x x x x x x x x x x x x x x x x x x x x x x x 0 1 2 3 0 1 2 i j 3 4 4 5 6 7 8 9
  7. a3 = 3 o x x x x x x

    x x x o o x x x x x x x x o o x x o o x x x x o o x o o o x o o x x x x x x x x x x x 0 1 2 3 0 1 2 i j 3 4 4 5 6 7 8 9
  8. a4 = 3 o x x x x x x

    x x x o o x x x x x x x x o o x x o o x x x x o o x o o o x o o x o o x o o o o o o x 0 1 2 3 0 1 2 i j 3 4 4 5 6 7 8 9
  9. 入力 #include<stdio.h> int main(){ int i, j; int n, x;

    scanf(“%d%d”,&n,&x); int a[105]; for(i = 1; i <= n; i++) scanf(“%d”,&a[i]); return 0; } #include<cstdio> using namespace std; int main(){ int n, x; scanf(“%d%d”,&n,&x); int a[105]; for(int i = 1; i <= n; i++) scanf(“%d”,&a[i]); return 0; } 4 9 1 4 3 3
  10. DPテーブルの初期化 #include<stdio.h> int dp[105][11005]; int main(){ int i, j; int

    n, x; scanf(“%d%d”,&n,&x); int a[105]; for(i = 1; i <= n; i++) scanf(“%d”,&a[i]); for(i = 0; i <= n; i++) for(j = 0; j <= x; j++) dp[i][j] = 0; dp[0][0] = 1; return 0; } #include<cstdio> using namespace std; bool dp[105][11005]; int main(){ int n, x; scanf(“%d%d”,&n,&x); int a[105]; for(int i = 1; i <= n; i++) scanf(“%d”,&a[i]); for(int i = 0; i <= n; i++) for(int j = 0; j <= x; j++) dp[i][j] = false; dp[0][0] = true; return 0; }
  11. かなめの部分 ུ for(i = 0; i <= n; i++) for(j

    = 0; j <= x; j++) dp[i][j] = 0; dp[0][0] = 1; for(i = 1; i <= n; i++){ for(j = 0; j <= x; j++){ } } return 0; } ུ for(int i = 0; i <= n; i++) for(int j = 0; j <= x; j++) dp[i][j] = false; dp[0][0] = true; for(int i = 1; i <= n; i++){ for(int j = 0; j <= x; j++){ } } return 0; }
  12. かなめの部分 ུ for(i = 1; i <= n; i++){ for(j

    = 0; j <= x; j++){ if(dp[i-1][j]){ dp[i][j] = 1; dp[i][j+a[i]] = 1; } } } if(dp[n][x] == 1) puts(“YES”); else puts(“NO”); return 0; } ུ for(int i = 1; i <= n; i++){ for(int j = 0; j <= x; j++){ if(dp[i-1][j]){ dp[i][j] = true; dp[i][j+a[i]] = true; } } } if(dp[n][x]) puts(“YES”); else puts(“NO”); return 0; }
  13. 完成! #include<stdio.h> int dp[105][11005]; int main(){ int i, j; int

    n, x; scanf(“%d%d”,&n,&x); int a[105]; for(i = 1; i <= n; i++) scanf(“%d”,&a[i]); for(i = 0; i <= n; i++) for(j = 0; j <= x; j++) dp[i][j] = 0; dp[0][0] = 1; for(i = 1; i <= n; i++){ for(j = 0; j <= x; j++){ if(dp[i-1][j] == 1){ dp[i][j] = 1; dp[i][j+a[i]] = 1; } } } if(dp[n][x] == 1) puts(“YES”); else puts(“NO”); return 0; } #include<cstdio> using namespace std; bool dp[105][11005]; int main(){ int n, x; scanf(“%d%d”,&n,&x); int a[105]; for(int i = 1; i <= n; i++) scanf(“%d”,&a[i]); for(int i = 0; i <= n; i++) for(int j = 0; j <= x; j++) dp[i][j] = false; dp[0][0] = true; for(int i = 1; i <= n; i++){ for(int j = 0; j <= x; j++){ if(dp[i-1][j]){ dp[i][j] = true; dp[i][j+a[i]] = true; } } } if(dp[n][x]) puts(“YES”); else puts(“NO”); return 0; }
  14. DPのバリエーション 表の作り方 例:フィボナッチ数列 → dp[i] = i番目の数字 多次元配列になることも多い 例:さっきの問題に「ちょうど M

    個の数字を使 う」っていう条件が加わったら、 dp[i][j][k] = a1..ai から j 個の数字を使って        和を k にできるかどうか 集合を要素にしたり、他にもいろいろ・・・
  15. 遊びの答え 4 2 3 3 2 4 3 2 3

    2 4 3 2 2 3 2 3 4 3 2 2 2 4 4 2
  16. 解き方 0 2 4 3 1 0 ? ? ?

    ? 最長距離 最初はこんな感じ
  17. 解き方 0 2 4 3 1 0 1 1 ?

    ? 最長距離 頂点0から1本の辺を辿って行ける頂 点の値を更新します
  18. 解き方 0 2 4 3 1 0 1 1 ?

    2 最長距離 頂点1に入ってくる辺は全て試したの で、頂点1の値は確定しました さっきと同じように更新していきます
  19. 解き方 0 2 4 3 1 0 1 1 2

    2 最長距離 頂点2の値が確定しました
  20. 解き方 0 2 4 3 1 0 1 1 2

    3 最長距離 すでに数字が書かれている時は、書か れている数字よりも大きくなる時だけ 更新します
  21. 解き方 0 2 4 3 1 0 1 1 2

    3 最長距離 できた! 答えは3! やったね!
  22. 解き方 0 2 4 3 1 0 1 1 2

    3 最長距離 要するに DP です!
  23. 実際の入力の例 5 6 0 1 0 2 1 4 2

    3 2 4 3 4 0 2 4 3 1 頂点の数 辺の数 辺の情報 0→1っていう辺が あるっていう意味
  24. vectorの使用例 int i; vector<int> a; for(i = 0; i <

    3; i++){ a.push_back(i+5); } for(i = 0; i < a.size(); i++){ printf(“%d\n”,a[i]); }
  25. シミュレーション int型の動的配列を作る。(まだ空っぽ) int i; vector<int> a; for(i = 0; i

    < 3; i++){ a.push_back(i+5); } for(i = 0; i < a.size(); i++){ printf(“%d\n”,a[i]); } a: 空っぽ
  26. シミュレーション a の一番後ろに i+5 を追加 a: 5 int i; vector<int>

    a; for(i = 0; i < 3; i++){ a.push_back(i+5); } for(i = 0; i < a.size(); i++){ printf(“%d\n”,a[i]); }
  27. シミュレーション ループが1回回って i = 1、末尾に i+5 を追加 a: 5 6

    int i; vector<int> a; for(i = 0; i < 3; i++){ a.push_back(i+5); } for(i = 0; i < a.size(); i++){ printf(“%d\n”,a[i]); }
  28. シミュレーション ループが回って i = 2、末尾に i+5 を追加 a: 5 6

    7 int i; vector<int> a; for(i = 0; i < 3; i++){ a.push_back(i+5); } for(i = 0; i < a.size(); i++){ printf(“%d\n”,a[i]); }
  29. シミュレーション a.size() は「a に入ってる要素の数」を表す a: 5 6 7 int i;

    vector<int> a; for(i = 0; i < 3; i++){ a.push_back(i+5); } for(i = 0; i < a.size(); i++){ printf(“%d\n”,a[i]); }
  30. シミュレーション 配列みたいに添字でアクセスできる a: 5 6 7 int i; vector<int> a;

    for(i = 0; i < 3; i++){ a.push_back(i+5); } for(i = 0; i < a.size(); i++){ printf(“%d\n”,a[i]); }
  31. 配列と見比べてみる int i; vector<int> a; for(i = 0; i <

    3; i++){ a.push_back(i+5); } for(i = 0; i < a.size(); i++){ printf(“%d\n”,a[i]); } int i; int a[3]; for(i = 0; i < 3; i++){ a[i] = i+5; } for(i = 0; i < 3; i++){ printf(“%d\n”,a[i]); } ほぼ同じような感じ
  32. こんな感じになる 0 2 4 3 1 1 2 0 1

    2 3 4 3 4 4 4 5 6 0 1 0 2 1 4 2 3 2 4 3 4 to
  33. Hello world! ほとんどいっしょだね! #include<stdio.h> int main(){ printf(“Hello world!”); return 0;

    } #include<cstdio> using namespace std; int main(){ printf(“Hello world!”); return 0; }
  34. C++とCでちょっと違うところ includeするもの → 例: stdio.h -> cstdio → 一応 stdio.h

    でも問題ない using namespace std; → 最初はなんにも考えずにとりあえずおまじな いとして書いとけば良い
  35. 頂点数と辺数の入力 #include<cstdio> using namespace std; int main(){ int n, m;

    scanf(“%d%d”,&n,&m); return 0; } n = 頂点数 m = 辺数 多くの問題ではこんな 変数名が付いている
  36. グラフの入力 #include<cstdio> #include<vector> using namespace std; int main(){ int n,

    m; scanf(“%d%d”,&n,&m); vector<int> to[1005]; for(int i = 0; i < m; i++){ } return 0; } n = 頂点数 m = 辺数 to = グラフ
  37. グラフの入力 #include<cstdio> #include<vector> using namespace std; int main(){ int n,

    m; scanf(“%d%d”,&n,&m); vector<int> to[1005]; for(int i = 0; i < m; i++){ int v, u; scanf(“%d%d”,&v,&u); to[v].push_back(u); } return 0; } n = 頂点数 m = 辺数 to = グラフ
  38. 最長距離リストの初期化 ུ vector<int> to[1005]; for(int i = 0; i <

    m; i++){ int v, u; scanf(“%d%d”,&v,&u); to[v].push_back(u); } int dist[1005]; for(int i = 0; i < n; i++) dist[i] = -1000000000; dist[0] = 0; return 0; } n = 頂点数 m = 辺数 to = グラフ dist = 距離
  39. かなめの部分 ུ int dist[1005]; for(int i = 0; i <

    n; i++) dist[i] = -1000000000; dist[0] = 0; for(int v = 0; v < n; v++){ } return 0; } n = 頂点数 m = 辺数 to = グラフ dist = 距離 0 2 4 3 1 0 1 1 ? ? 0 2 4 3 1 0 1 1 2 2
  40. かなめの部分 ུ for(int v = 0; v < n; v++){

    for(int i = 0; i < to[v].size(); i++){ } } return 0; } n = 頂点数 m = 辺数 to = グラフ dist = 距離 0 2 4 3 1 0 1 1 ? ? 0 2 4 3 1 0 1 1 2 2
  41. かなめの部分 for(int v = 0; v < n; v++){ for(int

    i = 0; i < to[v].size(); i++){ int u = to[v][i]; dist[u] = max(dist[u], dist[v]+1); } } printf(“%d\n”,dist[n-1]); n = 頂点数 m = 辺数 to = グラフ dist = 距離 max(x,y):大きい方を返す関数 algorithmをincludeすると使える #include<algorithm>
  42. 完成! #include<cstdio> #include<vector> #include<algorithm> using namespace std; int main(){ int

    n, m; scanf(“%d%d”,&n,&m); vector<int> to[1005]; for(int i = 0; i < m; i++){ int v, u; scanf(“%d%d”,&v,&u); to[v].push_back(u); } int dist[1005]; for(int i = 0; i < n; i++) dist[i] = -1000000000; dist[0] = 0; for(int v = 0; v < n; v++){ for(int i = 0; i < to[v].size(); i++){ int u = to[v][i]; dist[u] = max(dist[u], dist[v]+1); } } printf(“%d\n”,dist[n-1]); return 0; }
  43. おまけの答え #include<cstdio> #include<vector> #include<algorithm> using namespace std; int main(){ int

    n, m; scanf(“%d%d”,&n,&m); vector<int> to[1005]; for(int i = 0; i < m; i++){ int v, u; scanf(“%d%d”,&v,&u); to[v].push_back(u); } int dist[1005]; for(int i = 0; i < n; i++) dist[i] = 1000000000; dist[0] = 0; for(int v = 0; v < n; v++){ for(int i = 0; i < to[v].size(); i++){ int u = to[v][i]; dist[u] = min(dist[u], dist[v]+1); } } printf(“%d\n”,dist[n-1]); return 0; } #include<cstdio> #include<vector> #include<algorithm> using namespace std; int main(){ int n, m; scanf(“%d%d”,&n,&m); vector<int> to[1005]; for(int i = 0; i < m; i++){ int v, u; scanf(“%d%d”,&v,&u); to[v].push_back(u); } int count[1005]; for(int i = 0; i < n; i++) count[i] = 0; count[0] = 1; for(int v = 0; v < n; v++){ for(int i = 0; i < to[v].size(); i++){ int u = to[v][i]; count[u] = (count[u]+count[v])%1000000009; } } printf(“%d\n”,count[n-1]); return 0; } 最短距離 経路の数