标签:状压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