Particle

競技プログラミングについての雑記

SRM 651 Div1 Medium FoxConnection3

2次元グリッド上にきつねがN匹いる (N <= 6)
すべてのきつねが辺で連結になるように動かすとき、最小で何ステップでできるか?(きつねは重なることは出来ない)

まず、1次元の場合には、中央値に寄せるのが一番効率がよい。 (N が偶数のときは、真ん中の2つの値の平均を中央値とする。)
2次元の場合にもできるだけ中央に寄せるのがよい。
中央に近づけたあとは、高々 5*5 マスのグリッド上にすべてのきつねがいることになるので、BFS で調べれば良い。(状態数は、高々25C6 (=177,100)で、遷移も高々24なので、map を使っても十分間に合う。)

vector<int> x, y, x2, y2;
int n;
map<vector<int>, int> dp;
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
int h, w;

struct UF {
	vector<int> par, rank, sz;
	
	void init(int n){
		par = rank = vector<int>(n, 0);
		sz = vector<int>(n, 1);
		for(int i = 0; i < n; i++){
			par[i] = i;
		}
	}
	
	int find(int x){
		if(par[x] == x){
			return x;
		}else{
			return par[x] = find(par[x]);
		}
	}

	int size(int x){
		return sz[find(x)];
	}
	
	void unite(int x, int y){
		x = find(x);
		y = find(y);
		if(x == y) return;
		
		if(rank[x] < rank[y]){
			par[x] = y;
			sz[y] += sz[x];
		}else{
			par[y] = par[x];
			if(rank[x] == rank[y]) rank[y]++;
			sz[x] += sz[y];
		}
	}
	
	bool same(int x, int y){
		return find(x) == find(y);
	}
};


class FoxConnection3 {
	public:
	bool check(vector<int> &v){
		UF uf;
		uf.init(n);
		rep(i, n) rep(j, n){
			int a = v[i]/w, b = v[i]%w, c = v[j]/w, d = v[j]%w;
			if(abs(a-c)+abs(b-d)==1) uf.unite(i, j);
		}
		return uf.size(0)==n;
	}
	void comp(vector<int> &x, ll &res){
		for(int i = 4; i >= 0; i--){
			int cnt = 0, cnt2 = 0;
			rep(j, n){
				if(x[j]==i) cnt++;
				else if(x[j]>i) cnt2++;
			}
			if(cnt==0){
				rep(j, n) if(x[j]>i) x[j]--;
				res += min(cnt2, n-cnt2);
			}
		}
	}
	long long minimalSteps(vector <int> x_, vector <int> y_) {
		x=x_;y=y_;
		n = x.size();
		x2=x; y2=y;
		sort(all(x2)); sort(all(y2));
		ll xx = ((ll)x2[n/2]+x2[(n-1)/2])/2, yy = ((ll)y2[n/2]+y2[(n-1)/2])/2;
		cerr<<xx<<endl;
		ll res = 0;
		rep(i, n){
			if(x[i]<xx-2){
				res += xx-2-x[i];
				x[i] = xx-2;
				rep(_, 2) rep(j, n) if(i!=j&&x[i]==x[j]&&y[i]==y[j]) x[i]++,res++;
			}
			if(y[i]<yy-2){
				res += yy-2-y[i];
				y[i] = yy-2;
				rep(_, 2) rep(j, n) if(i!=j&&x[i]==x[j]&&y[i]==y[j]) y[i]++,res++;
			}
			if(x[i]>xx+3){
				res += x[i]-xx-3;
				x[i] = xx+3;
				rep(_, 2) rep(j, n) if(i!=j&&x[i]==x[j]&&y[i]==y[j]) x[i]--,res++;
			}
			if(y[i]>yy+3){
				res += y[i]-yy-3;
				y[i] = yy+3;
				rep(_, 2) rep(j, n) if(i!=j&&x[i]==x[j]&&y[i]==y[j]) y[i]--,res++;
			}
		}
		rep(i, n) x[n-i-1] -= xx-2;
		rep(i, n) y[n-i-1] -= yy-2;
		comp(x, res);
		comp(y, res);
		h = w = 1;
		rep(i, n) chmax(h, x[i]+1);
		rep(i, n) chmax(w, y[i]+1);
		vector<int> v(n);
		rep(i, n) v[i] = x[i]*w+y[i];
		sort(all(v));
		dp[v] = 0;
		queue<vector<int>> q;
		q.push(v);
		while(true){
			vector<int> vv = q.front(); q.pop();
			int t = dp[vv];
			if(check(vv)) return res+t;
			for(auto &a: vv){
				int aa = a;
				rep(i, 4){
					int ax = aa/w+dx[i], ay = aa%w+dy[i];
					if(ax<0||ax>=h||ay<0||ay>=w) continue;
					a = ax*w+ay;
					vector<int> vv2(vv);
					int cnt = 0;
					rep(j, n) if(vv2[j]==a) cnt++;
					if(cnt>1) continue;
					sort(all(vv2));
					if(!dp.count(vv2)){
						dp[vv2] = t+1;
						q.push(vv2);
					}
				}
				a = aa;
			}
		}
	}
};