HDU 3377 Plan
来源:互联网 发布:淘宝知识产权申诉成功 编辑:程序博客网 时间:2024/06/03 13:44
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3377
题意:左上角出发走到右下角结束,每个格子有个分数。每个格子最多经过一次,可以不经过,求最大得分。
思路:这题要求一个简单路径,也就是说只有起点和终点是单插头,其余点都是双插头, 所以分类讨论一下转移即可。
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>using namespace std;#define LL long long#define Clean(x,y) memset(x,y,sizeof(x))int n,m;int pre,cur;int g[20][20];const int maxn = 1009999;int bit = 7;int inc = 3;int code[20];int vis[20];struct hash_table{ int head[10007] , next[maxn]; LL value[maxn] , state[maxn]; int size; void clear() { size = 0; Clean(head,-1); } void push( LL S , LL V ) { int index = S % 10007; for( int k = head[index]; k != -1; k = next[k] ) if ( state[k] == S ) { value[k] = max( value[k] , V ); return; } state[size] = S , value[size] = V; next[size] = head[index] , head[index] = size++; }}dp[2];void init(){ for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d",&g[i][j]);}inline void decode( LL S , int m ){ for( int i = 0; i <= m; i++ ) code[i] = S & bit , S >>= inc;}inline LL encode( int m ){ LL ans = 0; int now = 1; Clean(vis,-1); vis[0] = 0; for( int i = m; i >= 0; i-- ) { if ( -1 == vis[ code[i] ] ) vis[code[i]] = now++; code[i] = vis[ code[i] ]; ans <<= inc; ans |= code[i]; } return ans;}void DP( int x , int y , int k ){ decode( dp[pre].state[k] , m ); int left = code[y-1] , up = code[y]; code[y] = code[y-1] = 0; LL V = dp[pre].value[k]; if ( x == n && y == m ) { if ( ( !up && left ) || ( !left && up ) ) //单插头 { dp[cur].push( encode( m ) , V + g[x][y] ); } } else if ( x == 1 && y == 1 ) { if ( x < n ) code[y-1] = 1 , dp[cur].push( encode( m ) , V + g[1][1] ) , code[y-1] = 0; if ( y < m ) code[y] = 1 , dp[cur].push( encode( m ) , V + g[1][1] ); } else if ( !left && !up ) //不取该格子,无插头,则不产生插头 { dp[cur].push( encode(m) , V ); if ( x < n && y < m ) { code[y] = code[y-1] = bit; dp[cur].push( encode(m) , V + g[x][y] ); } } else if ( !left || !up ) //取该格子,有一个插头,还需要一个插头 { if ( x < n ) code[y-1] = left + up , dp[cur].push( encode(m) , V + g[x][y] );//下插头 code[y] = code[y-1] = 0; if ( y < m ) code[y] = left + up , dp[cur].push( encode(m) , V + g[x][y] );//右插头 } else if ( left != up ) //有两个插头且不成回路,即联通两个非联通路线 不能形成回路 { for( int i = 0; i <= m; i++ ) if( code[i] == left ) code[i] = up; dp[cur].push( encode( m ) , V + g[x][y] ); }}LL solve(){ cur = 0; dp[0].clear(); dp[0].push( 1 , 0 ); for( int i = 1; i <= n; i++ ) { pre = cur , cur ^= 1; dp[cur].clear(); for( int k = 0; k < ( dp[pre].size ); k++ ) dp[cur].push( dp[pre].state[k]<<inc , dp[pre].value[k] ); for( int j = 1; j <= m; j++ ) { pre = cur , cur ^= 1; dp[cur].clear(); for( int k = 0; k < dp[pre].size; k++ ) DP( i , j , k ); } } for( int k = 0; k < dp[cur].size; k++ ) if ( dp[cur].state[k] == 0 ) return dp[cur].value[k]; return 0;}int main(){ int cas = 0; while( scanf("%d%d",&n,&m) == 2 ) { init(); printf("Case %d: %lld\n",++cas,solve()); } return 0;}
0 0
- hdu 3377 Plan
- hdu 3377 Plan
- HDU 3377 Plan
- HDU 3377 Plan
- hdu 3377 Plan(插头dp)
- hdu 3377 Plan 插头dp
- HDU 2103 Family Plan
- hdu 3757 Evacuation Plan
- HDU 4671 Backup Plan
- hdu-4671 Backup Plan
- HDU 4671 Backup Plan
- HDU 3757 Evacuation Plan
- Secrete Master Plan HDU
- HDU-3757-Evacuation Plan
- HDU 3377 Plan 解题报告(插头DP)
- HDU 4671 Backup Plan (水题)
- hdu 4671 Backup Plan 构造
- hdu 1964 Plan (插头dp)
- 【软考】—面向对象总结
- 接口
- putnik
- 用集合存储学生成绩,打印输出学生成绩及等级
- 程序功能:建立一个带有头结点的单向链表,并将存储在数组中的字符依次转储到链表的各个结点中。
- HDU 3377 Plan
- 安卓Andriod使用入门(三)【2048游戏】
- 拷贝函数
- Android应用的几种开发方式
- 实现qq中按返回键返回桌面不退出程序
- 双重二分查找的应用
- poj 3694 Network (tarjan+树链剖分)
- 如何在浏览器控制台(console)里输出彩色样式调试信息
- Python类属性,实例属性