zoukankan      html  css  js  c++  java
  • [TopCoder 12519]ScotlandYard

    CIV.[TopCoder 12519]ScotlandYard

    我们考虑一个最原始的DP状态:\(f[\mathbb{S}]\)表示根据当前给出的信息,猜的人可以推测出当前藏的人一定在且仅在集合\(\mathbb{S}\)之中时,藏的人最多可以走多少步。

    然后考虑枚举藏的人下一步给出走了什么颜色的边,然后取\(\mathbb{S}\)中所有点当前颜色的出边集合的并集\(\mathbb{T}\),则有\(f(\mathbb{S})\leftarrow f(\mathbb{T})+1\)。边界状态为 \(f(\varnothing)=0\)\(f(\mathbb{S})=1\text{ when }|\mathbb{S}|=1\)

    观察可以发现,猜的人最终可以确定藏的人在哪里的前一刻,\(\mathbb{S}\)的大小:

    1. 如果\(\geq3\),显然只判断其中两个亦可;

    2. 如果\(=2\),显然可以根据此两个一路反推回去,即任意时刻\(|\mathbb{S}|\)都可以被缩减到\(2\)

    3. 如果\(\leq1\),此状态显然不合法,不可能出现。

    故我们发现任意时刻状态中仅需存储\(\mathbb{S}\)中两个数即可。这样状态数就缩小到\(O(n^2)\)级别了。则此时就可以直接按照上文所述DP了。采取记忆化搜索的方式DP,如果任意时刻发现搜索到成环了,则答案必为\(\infty\)

    代码(TC的格式):

    #include<bits/stdc++.h>
    using namespace std;
    class ScotlandYard{
    private:
    	const int inf=0x3f3f3f3f;
    	int n,f[60][60];
    	vector<int>g[60][3];
    	bool in[60][60];
    	int dfs(int x,int y){
    		if(in[x][y])return inf;
    		if(f[x][y]!=-1)return f[x][y];
    		in[x][y]=true;
    		f[x][y]=0;
    		for(int i=0;i<3;i++){
    			vector<int>v;
    			for(auto j:g[x][i])v.push_back(j);
    			for(auto j:g[y][i])v.push_back(j);
    			sort(v.begin(),v.end()),v.resize(unique(v.begin(),v.end())-v.begin());
    			if(v.size()==0){f[x][y]=max(f[x][y],0);continue;}
    			if(v.size()==1){f[x][y]=max(f[x][y],1);continue;}
    			for(int i=0;i<v.size();i++)for(int j=i+1;j<v.size();j++)f[x][y]=max(f[x][y],min(inf,dfs(v[i],v[j])+1));
    		}
    		in[x][y]=false;
    		return f[x][y];
    	}
    public:
    	int maxMoves(vector<string>taxi,vector<string>bus,vector<string>metro){
    		n=taxi.size();
    		for(int i=0;i<n;i++)for(int j=0;j<3;j++)g[i][j].clear();
    		for(int i=0;i<n;i++)for(int j=0;j<n;j++)if(taxi[i][j]=='Y')g[i][0].push_back(j);
    		for(int i=0;i<n;i++)for(int j=0;j<n;j++)if(bus[i][j]=='Y')g[i][1].push_back(j);
    		for(int i=0;i<n;i++)for(int j=0;j<n;j++)if(metro[i][j]=='Y')g[i][2].push_back(j);
    //		for(int i=0;i<3;i++){for(int j=0;j<n;j++){for(auto k:g[j][i])printf("%d ",k);puts("");}puts("");}
    		memset(f,-1,sizeof(f));
    		int res=0;
    		for(int i=0;i<n;i++)for(int j=i+1;j<n;j++)res=max(res,dfs(i,j));
    		return res>=inf?-1:res;
    	}
    }my;
    

  • 相关阅读:
    素数路径Prime Path POJ3126 素数,BFS
    Fliptile POJ3279 DFS
    Find the Multiple POJ1426
    洗牌Shuffle'm Up POJ3087 模拟
    棋盘问题 POJ1321 DFS
    抓住那只牛!Catch That Cow POJ3278 BFS
    Dungeon Master POJ2251 三维BFS
    Splitting into digits CodeForce#1104A
    Ubuntu下手动安装Nvidia显卡驱动
    最大连续子序列和
  • 原文地址:https://www.cnblogs.com/Troverld/p/14601221.html
Copyright © 2011-2022 走看看