NC6874C-光玉小镇
求从走完所有
再回到
所需的最小时间为多少,每经过一次T时间需要停
,走一步的时间是
.
若不能走完所有的,输出
,否则输出所需的最小时间。
Solution
状压DP+BFS
难点:有多个,我们需要先确定
的顺序。
注意到的范围,我们从状压DP的经典题TSP问题中得到启示,我们可以用状压DP来枚举每一种可能的顺序,因为题目本身不是让我们求顺序,而是让我们求最优顺序下的结果。
状态:表示当前在
状态下最后一个走的是第
个
的最小花费。
(这里的花费是不包含停下来的时间,因为停下来的时间可以最后算答案的时候直接加上)
表示从
到
的距离。
转移式:
初始化:
上式中出现了距离,所以我们需要写一个BFS来求某两点之间的距离,如果存在走不到
,我们返回
表示走不完所有的
。
复杂度:
:状压的时候将点数前移一个从0开始更为方便。
Code
#include <bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll N = 2e2 + 5;
struct node{
int x,y,z;
}Q[N*N];
int n,m,sx,sy,cnt,dis[20],e[20][20],f[1<<16][20];
ll t,ans=1e18;
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1,};
bool vis[N][N];
char s[N][N];
vector<pii> V;
int BFS(int sx,int sy,int ex,int ey){
memset(vis,false,sizeof(vis));
queue<node> q;
vis[sx][sy]=true;
q.push({sx,sy,0});
while(!q.empty()){
node t=q.front();
q.pop();
if(t.x==ex && t.y==ey) return t.z;
for(int i=0;i<4;i++){
int nx=t.x+dx[i];
int ny=t.y+dy[i];
int nz=t.z+1;
if(nx<0 || nx>=n || ny<0 || ny>=m || vis[nx][ny] || s[nx][ny]=='#') continue;
vis[nx][ny]=true;
q.push({nx,ny,nz});
}
}
return -1;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n>>m>>t;
memset(f,0x3f,sizeof(f));
for(int i=0;i<n;i++) cin>>s[i];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(s[i][j]=='S') sx=i,sy=j;
else if(s[i][j]=='T') V.emplace_back(i,j);
cnt=V.size();
for(int i=0;i<cnt;i++){
f[1<<i][i]=dis[i]=BFS(sx,sy,V[i].fi,V[i].se);
if(dis[i]==-1) return cout<<-1<<'\n',0;
}
for(int i=0;i<cnt;i++)
for(int j=i+1;j<cnt;j++)
e[i][j]=e[j][i]=BFS(V[i].fi,V[i].se,V[j].fi,V[j].se);
for(int i=0;i<(1<<cnt);i++)
for(int j=0;j<cnt;j++)
if((1<<j)&i) for(int k=0;k<cnt;k++)
if(!((1<<k)&i)) f[i|1<<k][k]=min(f[i|1<<k][k],f[i][j]+e[j][k]);
for(int i=0;i<cnt;i++) ans=min(ans,f[(1<<cnt)-1][i]+dis[i]+t*cnt);
cout<<ans<<'\n';
return 0;
}
京公网安备 11010502036488号