0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ABC051 の問題を解いてみました

Last updated at Posted at 2024-01-01

A問題

, にして出力すれば解くことができます。

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

int main(void){
  string s;
  cin >> s;
  for(int i = 0; i < s.size(); i++){
    if(s[i] == ',') cout << " "; // , なら   を出力
    else cout << s[i];
  }
  cout << endl;
}

B問題

典型的な TLE を回避する方法を使います。
$x, y$ がを決めると、$z = s - (x + y)$ にするしかないことを利用して、計算量を削減します。

に似ています。

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

int main(void){
  int k, s;
  cin >> k >> s;
  
  int ans = 0;
  for(int x = 0; x <= k; x++){
    for(int y = 0; y <= k; y++){
      int z = s - (x + y); // z を求める
      if(0 <= z && z <= k){ // z が条件を満たしているなら
        ans++;
      } 
    }
  }
  cout << ans << endl;
}

C問題

2つの点は、4方向全てから出入りしないといけないです。
そのため、最短ルートは自ずと決まってきます。
下の画像のようなルートをとる道筋を出力します。

(赤色の長さ = $ty - sy$ で、 青色の長さ = $tx - sx$)

image.png

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

int main(void){
  int sx, sy, tx, ty;
  cin >> sx >> sy >> tx >> ty;
  string s = "";
  
  for(int i = 0; i < ty - sy; i++){
    s += "U";
  }
  for(int i = 0; i < tx - sx; i++){
    s += "R";
  }
  for(int i = 0; i < ty - sy; i++){
    s += "D";
  }
  for(int i = 0; i < tx - sx; i++){
    s += "L";
  }
  
  s += "LU";
  
  for(int i = 0; i < ty - sy; i++){
    s += "U";
  }
  for(int i = 0; i < tx - sx; i++){
    s += "R";
  }
  
  s += "RDRD";
  
  for(int i = 0; i < ty - sy; i++){
    s += "D";
  }
  for(int i = 0; i < tx - sx; i++){
    s += "L";
  }
  
  s += "LU";
  
  cout << s << endl;
}
追加情報

この記事を書いたあとに知ったのですが、
string(n, ch);
と書くと、chをn個連結したものが返されるそうです。

D問題

最短経路が絡んでくる時に使うアルゴリズムといえば、ダイクストラ法やワーシャルフロイド法などがあります。
今回は、ワーシャルフロイド法を使って解いていきます。(どちらでも解ける)

ワーシャルフロイド法の解説記事↓

ワーシャルフロイド法を使えば、すべての頂点からすべての頂点への最短経路を求めることができます。(全点対間最短経路の距離を求められる)

回答のプログラムでは、まず辺の情報を配列で記録します。
そして、その配列のコピーの配列$copy$を作っておきます。
そして、ワーシャルフロイド法を行って、配列$graph_{i,j}$にiからjへの最短経路の距離を代入します。

  int ans = 0;
  for(int i = 0; i < n; i++){
    for(int j = i + 1; j < n; j++){
      if(graph[i][j] != 1e9 && copy[i][j] > graph[i][j]){
        ans++;
      }
    }
  }

このコードを見てください。
もともと1つの辺でiとjが繋がっていなかった場合は、$copy_{i,j}$の値は1e9です。
そして、グラフは連結で、制約より$graph_{i, j}$は必ず1e9未満の値になります。
つまり、上のコードのif文は、iとjがもともと1つの辺で繋がっていて、iからjへの最短経路がその辺ではなかったときにのみtrueを返します。
そして、その場合、iとjをつなぐ一つの辺はどの最短経路にも含まれません。
結局そこをもっと短く移動する方法があるからです。

よって、このif文でtrueを返した数が、どの最短経路にも含まれない辺の数です。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
//Created by karaju.

signed main(){
  int n, m;
  cin >> n >> m;
  vector<vector<int> > graph(n, vector<int>(n));
  vector<vector<int> > copy(n, vector<int>(n));
  
  for(int i = 0; i < n; i++){
    for(int j = 0; j < n; j++){
      if(i == j){
        graph[i][j] = 0;
      }
      else graph[i][j] = 1e9;
    }
  }
  
  for(int i = 0; i < m; i++){
    int a, b, c;
    cin >> a >> b >> c;
    a--; b--;
    graph[a][b] = copy[a][b] = graph[b][a] = copy[b][a] = c;
  }
  
  
  for(int i = 0; i < n; i++){
    for(int j = 0; j < n; j++){
      for(int k = 0; k < n; k++){
        graph[j][k] = min(graph[j][k], graph[j][i] + graph[i][k]);
        //iを経由したほうが短いかを試す
      }
    }
  }
  
  int ans = 0;
  for(int i = 0; i < n; i++){
    for(int j = i + 1; j < n; j++){
      if(graph[i][j] != 1e9 && copy[i][j] > graph[i][j]){
        ans++;
      }
    }
  }
  cout << ans << endl;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?