Topcoder 12519 ScotlandYard(點對 dp+最長路)
阿新 • • 發佈:2020-11-30
題意:
有兩個人 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; //}