読者です 読者をやめる 読者になる 読者になる

minimum spanning treeを作る

久しぶりの技術ブログ

今回minimum spanning treeを作る目的
・対象ノードの関係をみる
・グラフをスパースにして視覚的に見やすくする!

・minimum spanning treeとは
グラフにリンクと距離が与えられたとき,重みの総和が最小になるように辺を選んで作った全域木

参考文献
[http://d.hatena.ne.jp/mickey24/20090605/1244132474:@さんのブログ]
ここを見れば完璧に理解できます


流れ
・入力

7 7 1
2 2:7.0 4:5.0 1 1
4 1:7.0 3:8.0 4:9.0 5:7.0 1 1
2 2:8.0 5:5.0 1 1
4 1:5.0 2:9.0 5:15.0 6:6.0 1 1
4 2:7.0 3:8.0 4:15.0 6:8.0 1 1
3 4:6.0 5:8.0 7:11.0 1 1
2 5:9.0 6:11.0 1 1

ノード数を1行目
2行目以降はリンク先ノードIDとその距離になってます


・処理
クラスカル法で求める

・出力

7 7 1
2 4:1 2:1 1 1
2 1:1 5:1 1 1
1 5:1 1 1
2 1:1 6:1 1 1
3 3:1 2:1 7:1 1 1
1 4:1 1 1
1 5:1 1 1

ノード数を1行目
2行目以降はリンク先ノードID(後につく:1は仕様)


プログラム
相変わらず汚いプログラムですね

#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <vector>
#include <algorithm>

using namespace std;
int Dm;
std::vector< int > VecA;//node cluster
std::vector< vector<int> > MatA;//spanning tree
std::vector< vector<int> > MatB;//各クラスタに属するノードID

class Init{
public:
  int from,to;
  double distance;
  std::vector<Init> FT;
  bool operator<(const Init &comp) const
  {
    if(this->distance < comp.distance) {
      return true;
    }else{
      return false;
    }
  }
  void readlbl(char *fn1);
  void printValue(char *fn1);
  void calValue();
};

void Init::readlbl(char *fn1)
{
  ifstream fin;
  int i,j,sum,Dn,k,l,m,Dc;
  char c;
  double d;
  Init tmp;
  fin.open(fn1);
  if(!fin){
    cerr << "ERROR: Failed to open file" << endl;
    exit(1);
  }
  fin >> Dm >> Dn >> Dc;
  for(i=0;i<Dm;i++){
    fin >> sum;
    tmp.from = i;
    for(j=0;j<sum;j++){
      fin >> k >> c >> d;
      tmp.to = k-1;
      tmp.distance = d;
      FT.push_back(tmp);
    }
    fin >> l >> l;
  }
  fin.close();
  std::stable_sort(FT.begin(),FT.end());
}

void initValue(){
  int i,j,k;
  MatA.resize(Dm);
  MatB.resize(Dm);
  VecA.resize(Dm);
  for(i=0;i<Dm;i++){
    MatB[i].resize(1);
    MatB[i][j] = i; 
    VecA[i] = i;
  }
}

void Init::calValue(){
  int i,j,before,after;
  Init cls;
  for(i=0;i<FT.size();i++){
    if(VecA[FT[i].to]!=VecA[FT[i].from]){
      MatA[FT[i].to].push_back(FT[i].from+1);
      MatA[FT[i].from].push_back(FT[i].to+1);
      if(VecA[FT[i].to] < VecA[FT[i].from]){
	before = VecA[FT[i].from];
	after = VecA[FT[i].to];
      }else{
	before = VecA[FT[i].to];
        after = VecA[FT[i].from];
      }
      for(j=MatB[before].size()-1;j>=0;j--){
	VecA[MatB[before][j]] = after;
	MatB[after].push_back(MatB[before][j]);
	MatB[before].pop_back();
      }
      if(MatB[after].size() == Dm) break;
    }else{
      continue;
    }
  }
}


void Init::printValue(char* fn1)
{
  ofstream fout;
  int i,j,Dn;
  fout.open(fn1);
  fout << Dm << " " << Dm << " " << 1 << endl;
  for(i = 0; i < Dm; i++){
    fout << MatA[i].size() << " ";
    for(j=0;j<MatA[i].size();j++){
      fout << MatA[i][j] << ":1 ";
    }
    fout << "1 1" << endl;
  }
  fout.close();
}


int main(int argc, char **argv){
  int i;
  Init cls;
  cls.readlbl(argv[1]);
  cout << "read ok\n";
  initValue();
  cout << "init ok\n";
  cls.calValue();
  cout << "cal ok\n";
  cls.printValue(argv[2]);
  cout << "print OK\n";
}


データの詳細は明かせませんがこんなグラフが書けました.

f:id:A_Koide0519:20120531234750p:image


f:id:A_Koide0519:20120531235039p:image