【TC SRM 312 Div1 Level3】CheapestIsland(轮廓线DP)(最小表示法)

传送门


随便抓了一道题来复习轮廓线DP。
听说和【JLOI2009 神秘的生物】本质上是一样的,没看,不清楚。

题解:

给一个棋盘图,每个格子有权值,求权值之和最小的连通块。

没什么难度,熟悉轮廓线的可以一眼出正解。

压一下轮廓线上点的连通情况,由于转移是四连通,所以我们只能用最小表示法。

最坏情况就是五列拉下来,有5个连通块。

直接上8进制压一下状态就行了。众所周知,在轮廓线DP中,最小表示法有一大堆无用状态,所以直接上哈希表优化一下就行了。

转移的话,我们直接考虑选不选这个格子,不选它就判断一下会不会导致它上方的格子所在连通块绝后。如果要选择,就看一下合并连通块还是新建连通块。

每次更新状态都要重新 O ( m ) O(m) O(m)标号,复杂度 O ( ⌊ m + 1 2 ⌋ m m 2 n ) O(\lfloor\frac{m+1}{2}\rfloor^mm^2 n) O(2m+1mm2n),但是无用状态实在太多了。。。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;

class Map{
	private:
		static cs int mogic=1898579;
		inline int locate(int k)cs{
			int h=k%mogic;
			while(key[h]!=-1&&key[h]!=k)h=h+1==mogic?0:h+1;
			return h;
		}
	public:
		int key[mogic],val[mogic];
		int st[mogic],tp,waste;
		Map(){memset(key,-1,sizeof key);tp=0;}
		inline void clear(){
			for(int re i=1;i<=tp;++i){
				key[st[i]]=-1;
				val[st[i]]=0;
			}tp=0;
		}
		cs int &operator[](int k)cs{
			int h=locate(k);
			return key[h]==k?val[h]:waste;
		}
		int &operator[](int k){
			int h=locate(k);
			if(key[h]==-1){
				key[h]=k,val[h]=0;
				st[++tp]=h;
			}
			return val[h];
		}
		bool find(int k)cs{return key[locate(k)]==k;}
};

class CheapestIsland{
	private:
		static cs int SIZE=6e5+5;
		int n,m,ans;
		int w[15][15];
		int state[SIZE],va[SIZE],tp;Map mp;
		inline int get(int s,int t){if(t<0)return 0;return s>>(t*3)&7;}
		inline int set(int s,int t,int st){if(t<0)return s;return s-((get(s,t)-st)<<(t*3));}
		inline bool other(int s,int st){
			bool flag=false;
			for(int re i=0;i<m;++i){
				if(get(s,i)==st)if(flag)return true;
				else flag=true;
			}
			return false;
		}
		inline void relable(int &s){
			int tot=0,id[15]={0};
			for(int re i=0;i<m;++i){
				int t=get(s,i);if(!t)continue;
				s=set(s,i,id[t]?id[t]:id[t]=++tot);
			}
		}
		inline bool final_check(int s){
			int ct=0;
			for(int re i=0;i<m;++i){
				ct=ct||get(s,i)==1;
				if(get(s,i)>1)return false;
			}
			return ct;
		}
		inline void update(int s,int val){
			relable(s);if(final_check(s))ans=std::min(ans,val);
			if(mp.find(s))mp[s]=std::min(mp[s],val);
			else mp[s]=val;
		}
	public:
		CheapestIsland(){}
		int minCost(std::vector<std::string> cell){
			n=cell.size();ans=0,m=1;
			for(int re i=1;i<cell[0].size();++i)if(cell[0][i]==' ')++m;
			for(int re i=0;i<n;++i){
				std::stringstream ss(cell[i]);
				for(int re j=0;j<m;++j)ss>>w[i][j];
			}
			update(0,0);
			for(int re i=0;i<n;++i)
			for(int re j=0;j<m;++j){
				for(int re k=1;k<=mp.tp;++k){
					state[k]=mp.key[mp.st[k]];
					va[k]=mp.val[mp.st[k]];
				}tp=mp.tp;mp.clear();
				for(int re k=1;k<=tp;++k){
					int s=state[k],v=va[k];
					int t1=get(s,j-1),t2=get(s,j);
					if(!t2||other(s,t2))update(set(s,j,0),v);
					if(!t1&&!t2)update(set(s,j,7),v+w[i][j]);
					else { 
						int id=std::max(t1,t2);s=set(s,j,id);
						for(int re t=0;t<m;++t)
						if(get(s,t)&&get(s,t)==std::min(t1,t2))
						s=set(s,t,id);
						update(s,v+w[i][j]);
					}
				}
			}
			return ans;
		}
};

#ifdef zxyoi

CheapestIsland Solver;

signed main(){
	std::cout<<Solver.minCost(
	
{"-1 -1 2 -1 -1",
"-1 -1 3 -1 -1",
"-1 -1 1 -1 -1",
"99 99 99 99 99",
"-1 -1 -1 -1 -1",
"-1 -1 -1 -1 -1"}

	)<<"\n";
	return 0;
}

#endif
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值