HDU 4568【最短路+状压DP】
2015-09-03 16:56
561 查看
应该算是比较裸的最短路和状压DP。。。感觉之前看到的题都是DP。。因为想的问题都一样。
有一点,由于状态在转移的时候,是由哪一个点转移过来的很重要,所以并不能通过取最小值来决定从哪一个点转移来,所以每个点产生的情况都要记录。在这里错了好久。。。
恩。。这样说来应该还是蛮简单的。。。。
有一点,由于状态在转移的时候,是由哪一个点转移过来的很重要,所以并不能通过取最小值来决定从哪一个点转移来,所以每个点产生的情况都要记录。在这里错了好久。。。
恩。。这样说来应该还是蛮简单的。。。。
#include <stdio.h> #include <iostream> #include <string.h> #include <queue> using namespace std; #define maxn 211 #define maxdp 10110 #define inf 0x3f3f3f3f int d[14][maxn][maxn]; int a[maxn][maxn]; int n,m,num,flag; int vis[maxn][maxn]; int visdp[14][maxdp],dp[14][maxdp]; queue<pair<int,int>>que; int dx[4]={1,-1,0,0}; int dy[4]={0,0,1,-1}; class node { public: int x,y; int minn,cost; }p[14]; bool check(int x,int y) { if(x<0||x>=n||y<0||y>=m) return false; if(a[x][y]==inf) return false; return true; } int min(int x,int y){return x<y?x:y;} int max(int x,int y){return x>y?x:y;} void SPFA() { memset(vis,0,sizeof(vis)); for(int i=0;i<num;i++) { int x=p[i].x,y=p[i].y; d[i][x][y]=0; que.push(make_pair(x,y)); vis[x][y]=1; while(que.size()) { x=que.front().first,y=que.front().second; que.pop(); vis[x][y]=0; for(int j=0;j<4;j++) { int tx=x+dx[j],ty=y+dy[j]; if(check(tx,ty)) if(d[i][x][y]+a[tx][ty]<d[i][tx][ty]) { d[i][tx][ty]=d[i][x][y]+a[tx][ty]; if(!vis[tx][ty]) que.push(make_pair(tx,ty)),vis[tx][ty]=1; } } } p[i].minn=inf; for(int j=0;j<m;j++) p[i].minn=min(p[i].minn,min(d[i][0][j],d[i][n-1][j])); for(int j=0;j<n;j++) p[i].minn=min(p[i].minn,min(d[i][j][0],d[i][j][m-1])); if(p[i].minn>=inf) {flag=1;break;} } } void Tosoon() { for(int i=0;i<num;i++) for(int j=0;j<maxdp;j++) dp[i][j]=inf; } void Search() { memset(visdp,0,sizeof(visdp)); Tosoon(); int maxnum=(1<<num); if(num==1) { int ans=p[0].minn*2+p[0].cost; if(ans>=inf) cout<<0<<endl; else cout<<ans<<endl; return; } for(int i=0;i<maxnum;i++) { for(int j=0;j<num;j++) { int now=(1<<j)|i; if(!i) dp[j][now]=p[j].minn+p[j].cost,visdp[j][now]=1; else { int jj=1<<j; if(i&jj) continue; for(int k=0;k<num;k++) { if(!visdp[k][i]||d[k][p[j].x][p[j].y]>=inf) continue; dp[j][now]=min(dp[j][now],dp[k][i]+d[k][p[j].x][p[j].y]); visdp[j][now]=1; } } } } int ans=inf; for(int i=0;i<num;i++) ans=min(ans,dp[i][maxnum-1]+p[i].minn); if(ans>=inf) {cout<<0<<endl;return;} cout<<ans<<endl; } void init() { for(int i=0;i<14;i++) for(int j=0;j<maxn;j++) for(int k=0;k<maxn;k++) d[i][j][k]=inf; } int main() { int T; cin>>T; while(T--) { init(); flag=0; cin>>n>>m; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { cin>>a[i][j]; if(a[i][j]==-1) a[i][j]=inf; } cin>>num; for(int i=0;i<num;i++) { cin>>p[i].x>>p[i].y; p[i].cost=a[p[i].x][p[i].y]; if(p[i].cost==inf) flag=1; } SPFA(); if(flag){cout<<0<<endl;continue;} Search(); } return 0; }
相关文章推荐
- 各种杂项组件(3)之--CalendarView(日历视图)、DatePicker/TimePicker(日期、时间选择器)、NumberPicker(数值选择器)
- PhotoView源码分析(1)
- 原型继承
- c++ primer读书笔记之c++11(三)
- 一对多的单项关联
- linux之用户管理
- 4.Realm(数据处理,交互)
- Unity3D学习笔记《Space Shooter》二
- C语言实验题——三个数排序
- 将两个数组合并并排序
- 第31-35课
- BZOJ 1026: [SCOI2009]windy数( dp )
- 已知: 每个飞机只有一个油箱, 飞机之间可以相互加油(注意是相互,没有加油机) 一箱油可供一架飞机绕地球飞半圈,问题:为使至少一架飞机绕地球一圈回到起飞时的飞机
- 检测出运动目标后提取边界 两个函数 cvFindContours和cvBoundingRect
- Windows内核编程基础篇之获得当前滴答数
- VS2010中“工具>选项中的VC++目录编辑功能已被否决”解决方法
- rdb快照持久化
- hdu 1864 最大报销额(非整数背包)
- NOI 2006 最大获利(最大权闭合)
- 寻找数组中的最大值和最小值