ural1519

https://vjudge.net/problem/URAL-1519

插头dp。。。

终于A掉了。。。抄了一个板子。。。

看那个ccy大神的博客 写的非常好。。。

讲几个问题:插头就是线穿过格子的边缘 左插头就是竖着的轮廓线左边 右插头就是竖着的轮廓线右边。。。我好想没用到这个概念。。。

然后就是各种分类讨论。。。

dp初值:dp[0][0]=1 第0行状态为0的方案数为1 

这个东西还是抄一下吧。。。

hash版:仿写的 跑的很快 那个hash不是很懂

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int N = 199917, M = 20, lim = 199917;
int n, m, k, endx, endy;
int a[M][M], tot[2]; //每种方案的总和//存哈希值 
ll ans;
ll Hash[N], state[2][N], sum[2][N], bin[M];
void hash(ll s, ll delta)
{ //把状态哈希成数值 
    int pos = s % lim;
    while(Hash[pos])
    {
        if(state[k][Hash[pos]] == s)
        {
            sum[k][Hash[pos]] += delta;
            return;
        }
        ++pos;
        if(pos == lim) pos = 0;
    }
    ++tot[k];
    Hash[pos] = tot[k];
    state[k][tot[k]] = s; sum[k][tot[k]] = delta;
}
void solve()
{
    tot[0] = sum[0][1] = 1;
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= m; ++j)
        {
//            printf("i=%d j=%d\n", i, j);
            k ^= 1;
            memset(Hash, 0, sizeof(Hash));
            memset(sum[k], 0, sizeof(sum[k]));
            memset(state[k], 0, sizeof(state[k]));
            tot[k] = 0;
            for(int t = 1; t <= tot[k ^ 1]; ++t)
            {        
                ll s = state[k ^ 1][t];
                int p = (s >> bin[j - 1]) % 4;
                int q = (s >> bin[j]) % 4;
                ll delta = sum[k ^ 1][t];
//                printf("s=%d p=%d q=%d delta=%d\n", s, p, q, delta);
                if(!a[i][j])
                { //障碍物 
                    if(!p && !q) hash(s, delta);
                    continue;
                }
                if(!p && !q)
                {
                    if(a[i][j + 1] && a[i + 1][j])
                    { //能不能伸出插头 
//                        printf("bin[j]=%d\n", bin[j]);
                        s = s + (1 << bin[j - 1]) + (1 << bin[j]) * 2;  
                        hash(s, delta);
                    }
                    continue;
                }
                if(!p && q)
                { //有一个插头 
                    if(a[i][j + 1])  
                        hash(s, delta);
                    if(a[i + 1][j])
                    {
                        s = s + q * (1 << bin[j - 1]) - q * (1 << bin[j]);
                        hash(s, delta);                     
                    }
                    continue;
                }
                if(p && !q)
                {
                    if(a[i + 1][j])
                        hash(s, delta);
                    if(a[i][j + 1])
                    {
                        s = s - p * (1 << bin[j - 1]) + p * (1 << bin[j]);
                        hash(s, delta);
                    }
                    continue;
                }
                if(p == 1 && q == 1)
                {
                    int cnt = 1;
                    for(int v = j + 1; v <= m; ++v)
                    {
                        int t = (s >> bin[v]) % 4;
                        if(t == 1) ++cnt;
                        else if(t == 2) --cnt;
                        if(cnt == 0)
                        {
//                            printf("v1=%d\n", v);
                            s -= (1 << bin[v]);
                            break;
                        }
                    }
                    s -= p * (1 << bin[j - 1]) + q * (1 << bin[j]);
                    hash(s, delta);
                    continue;
                }
                if(p == 2 && q == 2)
                {
                    int cnt = 1;
                    for(int v = j - 2; v; --v)
                    {
                        int t = (s >> bin[v]) % 4;
                        if(t == 2) ++cnt;
                        else if(t == 1) --cnt;
                        if(cnt == 0)
                        {
//                            printf("v2=%d\n", v);
                            s += (1 << bin[v]);
                            break;
                        }
                    }
                    s -= 2 * (1 << bin[j - 1]) + 2 * (1 << bin[j]);
                    hash(s, delta);
                    continue;
                }
                if(p == 2 && q == 1)
                {
                    s -= 2 * (1 << bin[j - 1]) + (1 << bin[j]);
                    hash(s, delta);
                    continue;
                }
                if(p == 1 && q == 2)
                {
//                    printf("delta=%d\n", delta);
                    if(i == endx && j == endy) 
                        ans += delta;
                    continue;
                }
            }    
        }
        for(int i = 1; i <= tot[k]; ++i)
            state[k][i] <<= 2;
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i)
    {
         //每个括号用两位表示 
        char s[M]; scanf("%s", s + 1);
        for(int j = 1; j <= m; ++j) 
        {
            a[i][j] = (s[j] == '.');
            if(s[j] == '.')
            {
                endx = i;
                endy = j;
            }
        }
    }
    for(int i = 1; i <= max(n, m); ++i) bin[i] = i << 1;
    solve();
    printf("%llu\n", ans); 
    return 0;
}
View Code

set版:set直接hash判重 但是跑的很慢

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll; 
const int N = 600010, M = 20;
int n, m, k, endx, endy;
int a[M][M];
ll bin[M], st[N]; //每种方案的总和
map<ll, ll> sum[2];
set<ll> s[2]; //存哈希值 
ll ans;
void hash(ll state, ll delta)
{ //把状态哈希成数值 
    if(s[k].count(state))
    {
        sum[k][state] += delta;
        return;
    }
    s[k].insert(state);
    sum[k][state] = delta;
}
void solve()
{
    sum[0][0] = 1;
    s[0].insert(0);
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= m; ++j)
        {
//            printf("i=%d j=%d\n", i, j);
            k ^= 1;
            sum[k].clear();
            s[k].clear();
            for(set<ll>::iterator it = s[k ^ 1].begin(); it != s[k ^ 1].end(); ++it)
            {        
                ll s = *it;
                int p = (s >> bin[j - 1]) & 3;
                int q = (s >> bin[j]) & 3;
                ll delta;
                if(j == 1) delta = sum[k ^ 1][*it >> 2];
                else delta = sum[k ^ 1][*it];
//                printf("s=%d p=%d q=%d delta=%d\n", s, p, q, delta);
                if(!a[i][j])
                { //障碍物 
                    if(!p && !q) hash(s, delta);
                    continue;
                }
                if(!p && !q)
                {
                    if(a[i][j + 1] && a[i + 1][j])
                    { //能不能伸出插头 
                        s = s + (1 << bin[j - 1]) + (1 << bin[j]) * 2;  
                        hash(s, delta);
                    }
                    continue;
                }
                if(!p && q)
                { //有一个插头 
                    if(a[i][j + 1])  
                        hash(s, delta);
                    if(a[i + 1][j])
                    {
                        s = s + q * (1 << bin[j - 1]) - q * (1 << bin[j]);
                        hash(s, delta);                     
                    }
                    continue;
                }
                if(p && !q)
                {
                    if(a[i + 1][j])
                        hash(s, delta);
                    if(a[i][j + 1])
                    {
                        s = s - p * (1 << bin[j - 1]) + p * (1 << bin[j]);
                        hash(s, delta);
                    }
                    continue;
                }
                if(p == 1 && q == 1)
                {
                    int cnt = 1;
                    for(int v = j + 1; v <= m; ++v)
                    {
                        int t = (s >> bin[v]) & 3;
                        if(t == 1) ++cnt;
                        else if(t == 2) --cnt;
                        if(cnt == 0)
                        {
                            s -= (1 << bin[v]);
                            break;
                        }                        
                    }
                    s -= p * (1 << bin[j - 1]) + q * (1 << bin[j]);
                    hash(s, delta);
                    continue;
                }
                if(p == 2 && q == 2)
                {
                    int cnt = 1;
                    for(int v = j - 2; v; --v)
                    {
                        int t = (s >> bin[v]) & 3;
                        if(t == 2) ++cnt;
                        else if(t == 1) --cnt;
                        if(cnt == 0)
                        {
                            s += 1 << bin[v];
                            break;
                        }        
                    }
                    s -= 2 * (1 << bin[j - 1]) + 2 * (1 << bin[j]);
                    hash(s, delta);    
                    continue;
                }
                if(p == 2 && q == 1)
                {
                    s -= 2 * (1 << bin[j - 1]) + (1 << bin[j]);
                    hash(s, delta);
                    continue;
                }
                if(p == 1 && q == 2)
                {
                    if(i == endx && j == endy) 
                        ans += delta;
                    continue;
                }
            }    
        }
        int top = 0;
        for(set<ll>::iterator it = s[k].begin(); it != s[k].end(); ++it)
            st[++top] = ((*it) << 2);
        s[k].clear();
        while(top)
        {
            s[k].insert(st[top]);
            --top;    
        }
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i)
    {
        //每个括号用两位表示 
        char s[M]; scanf("%s", s + 1);
        for(int j = 1; j <= m; ++j) 
        {
            a[i][j] = (s[j] == '.');
            if(s[j] == '.')
            {
                endx = i;
                endy = j;
            }
        }
    }
    for(int i = 1; i <= max(n, m); ++i) bin[i] = i << 1;
    solve();
    printf("%llu\n", ans);
    return 0;
}
View Code

 

posted @ 2017-06-05 22:50  19992147  阅读(205)  评论(0编辑  收藏  举报