标签:状压dp
5 5 GDDSS SSSFS SYGYS SGSYS SSYSS 0 0
4
题目:机器人从F出发,走到G可以充电,走到Y关掉开关,D不能走进,要求把所有开关关掉,且电量最少,并求出该最小电量。
思路:因为我们必须要到的是 Y F, 可能到的是 G,我们把必须到的状态设置为 下面代码的all,所有的状态为len,然后根据当前状态可以更新哪些状态进行dp,这个题不清楚的地方是 G,题目说到了这个点可以充电,也可以不充电,可能下次来在充电,不过最好不要多想,到了G就充电吧
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<map>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)
#define eps 1e-8
typedef __int64 ll;
#define fre(i,a,b) for(i = a; i <b; i++)
#define mem(t, v) memset ((t) , v, sizeof(t))
#define ssf(a) scanf("%s",a)
#define sf(n) scanf("%d", &n)
#define sff(a,b) scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf printf
#define bug pf("Hi\n")
using namespace std;
#define INF 0x3f3f3f3f
#define N 20
char a[N][N];
int dis[N][N][N][N];
int k;
int n,m;
int first,all;
int dp[1<<16][16]; //dp[s][i] s状态下最后到达 i 点 还有的油
int step[4][2]={1,0,-1,0,0,1,0,-1};
int vis[N][N];
struct stud{
stud(){};
stud(int _x,int _y):x(_x),y(_y),time(0){}
stud(int _x,int _y,int _time):x(_x),y(_y),time(_time){}
int x,y;
int time;
}f[N*N];
inline bool judge(int x,int y)
{
if(x>=0&&x<n&&y>=0&&y<m) return true;
return false;
}
void bfs(int t)
{
queue<stud>q;
int i,j;
f[t].time=0;
q.push(f[t]);
stud cur;
cur=f[t];
dis[cur.x][cur.y][cur.x][cur.y]=0;
mem(vis,0);
vis[cur.x][cur.y]=1;
while(!q.empty())
{
cur=q.front();
q.pop();
fre(i,0,4)
{
int xx=cur.x+step[i][0];
int yy=cur.y+step[i][1];
if(judge(xx,yy)&&a[xx][yy]!='D'&&!vis[xx][yy])
{
dis[f[t].x][f[t].y][xx][yy]=cur.time+1; //起始点和这个点的距离
vis[xx][yy]=1;
q.push(stud(xx,yy,cur.time+1));
}
}
}
}
bool check(int now)
{
int i,j;
mem(dp,-1);
dp[1<<first][first]=now;
int cur,len=1<<k;
int to,ans=-1;
fre(cur,0,len)
fre(i,0,k)
{
if((cur&(all))==all) ans=max(ans,dp[cur][i]); //走过该走的点了
if(ans!=-1) return true;
if(!(cur&(1<<i))) continue; // cur 应该是走过 i 的
if(dp[cur][i]==-1) continue; //这种状态没有走到过
fre(to,0,k) //枚举下一个点
{
if(cur&(1<<to)) continue;
if(dis[f[i].x][f[i].y][f[to].x][f[to].y]==-1) continue; //两者无法到达
if(i==to) continue;
int time=dp[cur][i]-dis[f[i].x][f[i].y][f[to].x][f[to].y]; //从 i 走到 to 后剩下的油
if(time<0) continue;
int next=cur+(1<<to);
dp[next][to]=max(dp[next][to],time);
if(a[f[to].x][f[to].y]=='G') dp[next][to]=now; //如果现在到达的点 可以加油
//(其实我感觉这里是有bug的,可能别人先到这个点不加油,下一次到的时候加油)
}
}
return false;
}
int solve() //二分答案
{
int le,ri,mid;
int ans=300;
le=0;
ri=300;
int i=0;
while(le<=ri)
{
mid=(le+ri)>>1;
if(check(mid)) //判断mid可否满足条件
{
ans=mid;
ri=mid-1;
}
else
le=mid+1;
}
if(ans==300)
return -1;
return ans;
}
int main()
{
int i,j;
//freopen("in.txt","r",stdin);
while(~sff(n,m),n+m)
{
fre(i,0,n)
ssf(a[i]);
all=0;
k=0;
fre(i,0,n)
fre(j,0,m)
{
if(a[i][j]=='F')
{
all|=1<<k; //我们要走所有点的最终状态是 all
first=k;
f[k++]=stud(i,j);
}
else
if(a[i][j]=='Y')
{
all|=1<<k;
f[k++]=stud(i,j);
}
else
if(a[i][j]=='G')
f[k++]=stud(i,j);
}
int t,tt;
fre(i,0,20)
fre(j,0,20)
fre(t,0,20)
fre(tt,0,20)
dis[i][j][t][tt]=-1;
fre(i,0,k)
bfs(i); //求出任意两个点的距离
int ans=solve();
pf("%d\n",ans);
}
return 0;
}
标签:状压dp
原文地址:http://blog.csdn.net/u014737310/article/details/44303661