Topcoder 12519 ScotlandYard(点对 dp+最长路)

题面传送门

题意:
有两个人 A 和 B 玩一个游戏。游戏规则大致是这样的:
\(n\) 个城市和三种交通工具公交、地铁和出租车。
给出三个 \(n\times n\) 的字符矩阵 \(b,m,t\)\(b_{i,j}='Y'\) 表示从城市 \(i\) 可以通过公交到达城市 \(j\)\(b_{i,j}='N'\) 表示从城市 \(i\) 不可以通过公交到达城市 \(j\)\(m,t\) 同理。
现在 A 要选择一个起始城市 \(i\),但是 B 不知道这个城市的编号。小 A 每次可以通过某种交通工具到达另一个城市,并将乘坐的交通工具告诉 B。如果 B 猜出了小 A 当前所在的城市,或者小 B 动不了了,游戏结束。
A 的得分为 A 经过的边数。求 A 得分的最大值,如果游戏可能永远进行下去,输出 -1。
\(1 \leq n \leq 50\)

话说这题出现了两次呢。。。记得 CSP 前一周学校模拟赛某道题就是这个,结果昨天模拟赛又出现了一遍。。。今天终于见到这题的真面貌了(
\(S\) 为当前 A 当前可能位于的城市的集合。初始 \(S=\{1,2,\dots,n\}\)
如果小 A 搭乘了交通工具 \(x\),那么 \(S\) 就变为:\(S\) 中的点集通过交通工具 \(x\) 能到达的点。
答案就是最多进行多少次操作后 \(S\) 中剩一个点。
很容易想到 \(2^n\) 的做法,对于集合之间的相互转化关系连边,跑最长路。


其实并不用把集合中每个点都表示出来。
只需要找到两个代表点 \((i,j)\),对这些点对连边跑最长路就行了。
这样点的个数就降到了 \(n^2\)
至于 \(-1\) 的情况,就是判断对点对建立的图中有没有环,记忆化搜索/拓扑排序就可以了。
时间复杂度 \(n^4\),是道思维题(为啥就想不出来呢,wtcl)

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
typedef pair<int,int> pii;
typedef long long ll;
const int MAXN=50+5;
int n,dp[MAXN][MAXN],vis[MAXN][MAXN];
bool s1[MAXN][MAXN],s2[MAXN][MAXN],s3[MAXN][MAXN];
int dfs(int x,int y){
	if(x>y) swap(x,y);
	if(x==y) return 0;
	if(vis[x][y]) return 1e9;
	if(~dp[x][y]) return dp[x][y];
	vis[x][y]=1;dp[x][y]=0;
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
		if((s1[x][i]&&s1[y][j])||(s1[x][i]&&s1[x][j])||(s1[y][i]&&s1[y][j])||
		   (s2[x][i]&&s2[y][j])||(s2[x][i]&&s2[x][j])||(s2[y][i]&&s2[y][j])||
		   (s3[x][i]&&s3[y][j])||(s3[x][i]&&s3[x][j])||(s3[y][i]&&s3[y][j]))
				dp[x][y]=max(dp[x][y],dfs(i,j)+1);
	}
	vis[x][y]=0;return dp[x][y];
}
class ScotlandYard{
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<n;j++) s1[i+1][j+1]=(taxi[i][j]=='Y');
		for(int i=0;i<n;i++) for(int j=0;j<n;j++) s2[i+1][j+1]=(bus[i][j]=='Y');
		for(int i=0;i<n;i++) for(int j=0;j<n;j++) s3[i+1][j+1]=(metro[i][j]=='Y');
		int ans=0;memset(dp,-1,sizeof(dp));
		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) ans=max(ans,dfs(i,j));
		if(ans>=1e9) return -1;return ans;
	}
};
//ScotlandYard program;
//int main(){
//	int n;scanf("%d",&n);
//	vector<string> taxi,bus,metro;
//	for(int i=1;i<=n;i++){string s;cin>>s;taxi.pb(s);}
//	for(int i=1;i<=n;i++){string s;cin>>s;bus.pb(s);}
//	for(int i=1;i<=n;i++){string s;cin>>s;metro.pb(s);}
//	printf("%d\n",program.maxMoves(taxi,bus,metro));
//	return 0;
//}
posted @ 2020-11-30 18:40  tzc_wk  阅读(109)  评论(1编辑  收藏  举报