SRM 368 500pt: PolylineUnion

問題概要

線分からなる図形がいくつか与えられる。重なっているものをマージしていったとき、要素がいくつ残るか求める問題。

考えたこと

  • また入力が面倒な…。
  • 線分の個数とか大したことないし、やるだけ問題に思える。
  • 書いた。サンプル通らない。
  • 入力のパースが間違えてた。つまんない…。
  • サンプル通った。投げる。
  • 合わない。よく読んだら1点だけの図形とか、線分の癖に始点と終点が同じとかあるらしい。面倒くさい…。
  • 馬鹿にしてんのか、って言うくらい丁寧に書いたんだけど通らない。
  • union findの配列確保の数があってなかった。これだから入力面倒くさいのはいやなんだ。直したら通った。

practiceで通った解法

計算量O(線分の個数^2*線分の要素数^2)くらい。

#include <vector>
#include <string>
#include <sstream>
#include <numeric>
using namespace std;

typedef long long int64;

const int MAX_N = 100000;
int pars[MAX_N];
void init(int n){for(int i=0;i<n;i++)pars[i]=i;}
int getRoot(int x){return x==pars[x]?x:(pars[x]=getRoot(pars[x]));}
bool isSame(int x, int y){return getRoot(x)==getRoot(y);}
void merge(int x, int y){pars[getRoot(x)]=getRoot(y);}

struct PolylineUnion {

	int countComponents(vector <string> polylines) {

		//データの読み取り
		//string str = accumulate(polylines.begin(), polylines.end(), string());
		string str = "";
		for(int i=0; i<(int)polylines.size(); i++){
			str += polylines[i];
		}
		stringstream sss(str);
		polylines.clear();
		while(sss >> str){
			polylines.push_back(str);
		}
		const int N = polylines.size();
		vector< vector< pair<int,int> > >lines(N);
		for(int i=0; i<N; i++){
			for(int j=0; j<(int)polylines[i].length(); j++){
				if(polylines[i][j] == '-' || polylines[i][j] == ','){
					polylines[i][j] = ' ';
				}
			}
			stringstream ss(polylines[i]);
			int x, y;
			while(ss >> x >> y){
				lines[i].push_back( make_pair(x,y) );
			}
		}

		//union find
		init(N);
		for(int i=0; i<N; i++){
			for(int j=i+1; j<N; j++){
				if(cross(lines[i], lines[j])){
					merge(i,j);
				}
			}
		}

		//構成成分を数える
		int ret = 0;
		for(int i=0; i<N; i++)if(getRoot(i) == i){
			ret++;
		}

		return ret;
	}

	bool cross(const vector< pair<int,int> >& as, const vector< pair<int,int> >& bs){
		for(int i=0; i<(int)as.size()-1; i++){
			for(int j=0; j<(int)bs.size()-1; j++){
				if(sub_cross(as[i], as[i+1], bs[j], bs[j+1])){
					return true;
				}
			}
		}
		for(int i=0; i<(int)as.size(); i++){
			for(int j=0; j<(int)bs.size()-1; j++){
				if(is_on(bs[j], bs[j+1], as[i])){
					return true;
				}
			}
		}
		for(int i=0; i<(int)as.size()-1; i++){
			for(int j=0; j<(int)bs.size(); j++){
				if(is_on(as[i], as[i+1], bs[j])){
					return true;
				}
			}
		}
		for(int i=0; i<(int)as.size(); i++){
			for(int j=0; j<(int)bs.size(); j++){
				if(as[i] == bs[j]){
					return true;
				}
			}
		}
		return false;
	}

	bool sub_cross(const pair<int,int> a1, const pair<int,int> a2, const pair<int,int> b1, const pair<int,int> b2){
		return det(a1,a2,b1)*det(a1,a2,b2)<0 && det(b1,b2,a1)*det(b1,b2,a2)<0;
	}

	bool is_on(const  pair<int,int> p, const pair<int,int> q, const pair<int,int>a){
		int minx = min(p.first, q.first);
		int maxx = max(p.first, q.first);
		int miny = min(p.second, q.second);
		int maxy = max(p.second, q.second);
		int x = a.first, y = a.second;
		if(minx <= x && x <= maxx && miny <= y && y <= maxy && det(p,q,a)==0){
			return true;
		}
		return false;
	}

	int64 oprod(const pair<int,int> a, const pair<int,int> b){
		return (int64)a.first*b.second - (int64)a.second*b.first;
	}

	int det(const pair<int,int> a, const pair<int,int> b, const pair<int,int> c){
		return sign(oprod(a,b) + oprod(b,c) + oprod(c,a));
	}

	int sign(int64 x){
		return x>0?1:x==0?0:-1;
	}
};