HDU 1964 Pipes

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1964


題意:每個格子之間的牆壁有個花費,求用一個環經過每個格子僅一次的最小花費。求最小值花費。


思路:一個簡單的插頭dp,相當於一個n*m的地圖裏找一個單迴路覆蓋全部點的最小花費,每個點記錄向右走和向下走的花費。



#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod 100000007
const int maxn = 1000009;
const int Hash = 10007;
int n,m;
int bit = 7 , inc = 3;
int cur , pre;

int code[20];
int vis[20];
int g[12][12][2];

struct hash_table
{
    int head[Hash] , size;
    LL state[maxn];
    int next[maxn] , value[maxn];
    void clear()
    {
        size = 0;
        Clean(head,-1);
    }
    void push( LL S , int V )
    {
        int index = S % Hash;
        for( int k = head[index]; k != -1; k = next[k] )
            if ( state[k] == S )
            {
                value[k] = min(V,value[k]);
                return;
            }
        state[size] = S , value[size] = V;
        next[size] = head[index] , head[index] = size++;
    }
}dp[2];

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;
}

int pos( int x , int y )
{
    return ( x - 1 ) * m + y;
}

void init()
{
    char str[100];
    scanf("%d%d",&n,&m);
    getchar();
    gets(str);
    rep(i,1,n)
    {
        gets(str);
        rep(j,1,m-1) g[i][j][0] = str[2*j] - '0';
        if ( i != n )
        {
            gets(str+1);
            rep(j,1,m) g[i][j][1] = str[2*j] - '0';
        }
    }
    gets(str);
}

bool check()
{
    for( int i = 0 ; i <= m; i++ ) if ( code[i] ) return false;
    return true;
}

void DP( int x , int y , int k )
{
    decode( dp[pre].state[k] , m );
    int left = code[y-1] , up = code[y];
    code[y-1] = code[y] = 0;
    int V = dp[pre].value[k];
    if ( !left && !up )
    {
        if ( x < n && y < m )
        {
            code[y-1] = code[y] = bit;
            dp[cur].push( encode(m) , V + g[x][y][0] + g[x][y][1]);
        }
    }
    else if ( !left || !up )
    {
        if ( x < n ) code[y-1] = up + left , dp[cur].push( encode(m) , V + g[x][y][1] );
        code[y] = code[y-1] = 0;
        if ( y < m ) code[y] = up + left , dp[cur].push( encode(m) , V + g[x][y][0] );
    }
    else if ( left != up ) //合併不同的連通分量
    {
        for( int i = 0; i <= m; i++ )
            if ( code[i] == left ) code[i] = up;
        dp[cur].push( encode(m) , V );
    }
    else if ( x == n && y == m ) dp[cur].push( encode(m) , V );//在最後一個點形成迴路
}

void solve()
{
    dp[0].clear();
    dp[0].push( 0 , 0 );
    cur = 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 )
    {
        printf("%d\n",dp[cur].value[k]);
        return;
    }

}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        init();
        solve();
    }
    return 0;
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章