<p>吐槽一下,最近事情真是多。。。大创+大挑+考试+实验报告(一个礼拜5个实验。。。)+各种抄作业+帮四省赛装电脑,然后一直没怎么做题。。。</p><p>然后再吐槽一下这道题,读题不细心真是惨啊。。。一开始看成了G点和Y点分别不超过15个,想想,加起来用30个点,我去。。。这怎么搞。。。拼命搞了两天没搞出来。。。两天以后又看了一下题目,发现是一共加起来不超过15个点(醉了,难怪我英语可能要挂科了),这就是一个普通的TSP问题了,不过并不是遍历所有的点一次,而是选定的点各一次,这个时候加一个末状态就好了。先建图,每个点做一次bfs就好了(找出最短路径),dp[s][i]表示第s状态最后到达i点的最大剩余体力。转移方程就是dp[s][j] = max(dp[pre_s][i]-dis[i][j]),这里要注意一下边界问题。。。对于TSP问题,我总觉的我的写法比较奇葩(但是都过了,以后如果出问题了再改吧)。最近感觉c++迭代器里面的东西确实好用。。。</p><p>下面直接给代码</p>
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> #define ll long long #define FOR(i,x,y) for(int i = x;i < y;i ++) #define IFOR(i,x,y) for(int i = x;i > y;i --) using namespace std; typedef pair<int,int> pii; pii no[16]; int en,st,dis[16][16][16][16],n,N,M,dp[1<<16][16]; char mat[17][17]; int dx[4] = {-1,1,0,0},dy[4] = {0,0,-1,1}; void input(){ n = 0; en = 0; FOR(i,0,N){ scanf("%s",mat[i]); FOR(j,0,M){ if(mat[i][j] == 'F'){ st = n; en = en | (1<<n); no[n++] = make_pair(i,j); continue; } if(mat[i][j] == 'G'){ no[n++] = make_pair(i,j); continue; } if(mat[i][j] == 'Y'){ en = en | (1<<n); no[n++] = make_pair(i,j); continue; } } } } void bfs(pii um){ queue <pii> q; dis[um.first][um.second][um.first][um.second] = 0; q.push(um); while(!q.empty()){ pii u = q.front(); q.pop(); int x = u.first,y = u.second; FOR(i,0,4){ int nx = x + dx[i],ny = y + dy[i]; if(nx < 0 || nx >= N || ny < 0 || ny >= M) continue; if(mat[nx][ny] == 'D') continue; if(dis[um.first][um.second][nx][ny] != -1) continue; dis[um.first][um.second][nx][ny] = dis[um.first][um.second][x][y] + 1; q.push(make_pair(nx,ny)); } } } bool init(){ memset(dis,-1,sizeof(dis)); FOR(i,0,n){ bfs(no[i]); } FOR(i,0,n){ if(mat[no[i].first][no[i].second] != 'G' && dis[no[st].first][no[st].second][no[i].first][no[i].second] == -1) return false; } return true; } bool check(int p){ FOR(s,0,1<<n){ FOR(i,0,n) dp[s][i] = -1; } dp[1<<st][st] = p; FOR(s,0,1<<n){ if((s & (1<<st)) == 0) continue; FOR(j,0,n){ if((s & (1<<j)) == 0) continue; if(j == st) continue; int pre_s = s ^ (1<<j); FOR(i,0,n){ if((pre_s & (1<<i)) == 0) continue; int tem = dis[no[i].first][no[i].second][no[j].first][no[j].second]; if(tem == -1) continue; dp[s][j] = max(dp[pre_s][i]-tem,dp[s][j]); } if(dp[s][j] == -1) continue; if((s & en) == en && dp[s][j] != -1) return true; if(mat[no[j].first][no[j].second] == 'G') dp[s][j] = p; } } return false; } int solve(){ int l = 0,r = 1111111; check(2); while(l < r){ int mid = (l+r)>>1; if(!check(mid)) l = mid+1; else r = mid; } return l; } int main(){ //freopen("test.in","r",stdin); while(scanf("%d%d",&N,&M),(N || M)){ input(); if(en == (1<<st)) printf("0 "); else if(!init()) printf("-1 "); else printf("%d ",solve()); } return 0; }