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

NPCA合宿きょーぷろ講義

snuke
August 22, 2013

 NPCA合宿きょーぷろ講義

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; } 最短距離 経路の数