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
原创粉丝点击