poj 1636 Prison rearrangement (监狱调整)
来源:互联网 发布:企业淘宝认证资料 编辑:程序博客网 时间:2024/04/29 20:10
感想: 虽然本人也是看别人代码写出来的,但对于我这样的dp菜鸟,实在太有收获了,希望大家无论自己悟出来还是看别人的博客,都争取自己写出来,这题确实对练习dp的人太有益处了。
思路: 一开始就得弄清楚,1号房和2号房是互相联系的,有关系的,他们之间构成一个连通分量(这个必须得弄清楚,不然
后面的多重背包完全会想不通的),只要选取其中连通分量中的一个,其余的都要进行交换操作。
在开始输入完毕后就应该 深搜其连通分量,最坏的情况也就是这个点单独构成一个连通分量,相当于他的交换与外界无关系(此处需要注意的是,如果按照1号牢房来进行搜索,可能2号牢房中还有那些与外界无关系的牢友没有被考虑到,所以搜索得进行2次)。
dp[ i ][ j ]表示的是1号牢房交换i个人,2号牢房交换j个人。(dp数组是个bool数组,只需要判断其是否存在)。
最后的判断就变成判断dp[ i ][ i ]是否存在。
连通分量分好了之后,这就转化成一个01背包问题,只是这个01背包只是判断
状态转换方程:dp[k][i][j] = dp[k-1][i-a[k]][j-b[k]] || dp[k-1][i][j]。简单解释一下:dp[k][i][j]表示对前K组,用监狱A的i个人和监狱B的j个人交换是否成功。前K组的解与前K-1组有关。当前K-1组解决后,只要加上第K组就可以搞定前K组。对第K组有两种选择:选或不选。
慢慢看代码吧。
#include<cstdio>#include<cstring>#include<iostream>using namespace std;int r,m,asize,bsize;const int size = 205;bool vis[2][size],dp[size][size];/*//visited[0][i] 表示用1号牢房中的点i是否被访问过 //visited[1][i] 表示用2号牢房中的点i是否被访问过*/int map[size][size];void DFS(int side,int id)//side 分别为0,1表示此时访问的是哪个牢房,id就是这个牢房中牢友的编号{ vis[side][id] = true; if(side == 0) { asize++; for(int i=1;i<=m;++i) { if(map[id][i]&&!vis[1][i])//访问了的话就不访问了 { DFS(1,i); } } } else { bsize++; for(int i=1;i<=m;++i) { if(map[i][id]&&!vis[0][i]) DFS(0,i); } }}void kpack()//01背包的函数{ dp[0][0] = true; for(int i=m/2;i>=asize;--i) for(int j=m/2;j>=bsize;--j) { if(dp[i][j]||dp[i-asize][j-bsize]) dp[i][j] = true; }}int main(){ int T; cin>>T; while(T--) { memset(map,0,sizeof(map));//初始化得放在循环中,我就因为这个调了半天 memset(vis,false,sizeof(vis)); memset(dp,false,sizeof(dp)); cin>>m>>r; for(int i=1;i<=r;++i) { int a,b; cin>>a>>b; map[a][b] = 1; } for(int i=1;i<=m;++i)//从左边开始探究 这里是对那些组成连通分量的进行dp, { if(vis[0][i]) continue; asize = 0; bsize = 0; DFS(0,i); kpack(); } for(int i=1;i<=m;++i)//怕有剩下的右边的边,对右边的边进行连通分量进行dp { if(vis[1][i]) continue; asize = 0; bsize = 0; DFS(1,i); kpack(); } for(int i=m/2;i>=0;i--) if(dp[i][i]) { cout<<i<<endl; break; } } return 0;}
- poj 1636 Prison rearrangement (监狱调整)
- POJ 1636 Prison rearrangement
- poj 1636 Prison rearrangement
- poj 1636 Prison rearrangement
- POJ 1636 Prison rearrangement
- POJ 1636 Prison rearrangement
- POJ 1636 Prison rearrangement
- poj 1636 Prison rearrangement
- POJ 1636 Prison rearrangement
- 【poj 1636】Prison rearrangement dp
- POJ 1636 Prison rearrangement 笔记
- 监狱调整 POJ1636 Prison rearrangement 传递闭包FLoyd DFS 二维背包 动态规划DP
- 【poj 1636】Prison rearrangement dfs+01背包
- poj 1634 Prison rearrangement
- poj 1634 Prison rearrangement
- pku1636 Prison rearrangement
- (中等) 背包 HOJ 1293 Prison Rearrangement
- 菜鸟学算法之POJ1636 Prison Rearrangement
- jsp / servlet解决中文乱码
- 委托和协议
- faceTracking 的一些资源
- UltraEdit在win7中添加右键菜单
- android权限大全
- poj 1636 Prison rearrangement (监狱调整)
- Oracle 11g deferred_segment_creation 段延迟创建
- 使用VC6.0实现窗口的任意分割
- oracle 完整性约束
- ctags android 源代码目录
- ServletContext和ServletConfig的理解
- Fastdfs-apache-module结合使用
- gSOAP中文文档
- oracle 杀死死锁的方法