UVA - 1204 Fun Game-like pressure dp

topic

A ring, given n (n <= 16) string, the string is on the ring, find the minimum of the original loop is long

analysis

This question is very troublesome feeling, the key is a string of a given sequence may be clockwise, counterclockwise or may be, and also to determine the starting position, and finally even when the ring (that is, when connected end to end), how to ensure the ring is the smallest
at the beginning I misunderstood that gave BGGB and the fight is out of the BGG BGG instead BGGBGG, read the code after determining the substring all strings are ring, there is no cycle may

First pre-treatment, will be deleted other string string substring, there are many tips, I feel very simple, you can refer Liu Rujia code.
And because it is a ring, the [0] [0] 0 positive sequence strings as the starting dp [1] [0] [ 0] = len [0], update status brush table method
searches end of the string is determined result

First, the strings together into a line
state dp [s] [j] [ k] s is a collection of the representative set of string has been connected, j is the last of a string concatenation, k = 0 or 1 and j represents the sequence, dp [s] [j] [k] represents the length of overlapping the string s
and finally j (j need to determine comparative) and is connected to 0, subtracts the cover portion, may form a ring
state transition equation: for existing state s, is connected to the end of the string j, the order k, i can continue to add to his right string, i is the order of L, the following transfer equation
d p [ s ( 1 < < i ) ] [ i ] [ l ] = d p [ s ] [ j ] [ k ] + o v e r l a p [ j ] [ i ] [ k ] [ l ] dp[s|(1<<i)][i][l]=dp[s][j][k]+overlap[j][i][k][l]

Finally, if the result is 1, 2 to be output, because the subject of the request

to sum up

Or for-like pressure dp not familiar with this problem like using pressure dp is obvious, the question is how a string that represents the order (the order of an additional dimension represents the last of a string), use this question in a few tricks to simplify the calculation, it is noteworthy

//
// Created by Zhao Pengfei on 2019/11/14.
//
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <utility>
using namespace std;
const int maxn=16;
struct Item{
    string str,rev;
    bool operator < (const Item &rhs) const {
        return str.length()<rhs.str.length();
    }
};
//overlap[i][j][k][l]中,i,j代表两个字符串的序号,k代表i的顺序,l代表j的顺序
//dp[s][j][k]
int n,m,overlap[maxn][maxn][2][2],dp[1<<16][maxn][2],len[maxn];
Item items[maxn];
string s[maxn][2];   //小技巧,这样分成二维表示顺序,方便传入Overlap函数中计算,不用写if判断顺序

//a(left),b(right) overlap length
int Overlap(string &a,string &b){
    int len1=a.length();
    int len2=b.length();
    for(int i=0;i<len1;++i){
        if(i+len2<=len1) continue; //没有到能够重合的位置
        bool flag=true;
        for(int j=0;i+j<len1;++j){
            if(a[i+j]!=b[j]){
                flag=false;
                break;
            }
        }
        if(flag){
            return len1-i;
        }
    }
    return 0;
}

void Init(){
    //输入,预处理,删除被包含的子字符串
    for(int i=0;i<n;++i){
        cin>>items[i].str;
        items[i].rev=items[i].str;
        reverse(items[i].rev.begin(),items[i].rev.end());
    }
    sort(items,items+n);
    m=0;
    for(int i=0;i<n;++i){
        bool flag=true;
        for(int j=i+1;j<n;++j){
            if(items[j].str.find(items[i].str)!=string::npos
                ||items[j].str.find(items[i].rev)!=string::npos ) {
                flag = false;
                break;
            }
        }
        if(flag){
            s[m][0]=items[i].str;
            s[m][1]=items[i].rev;
            len[m]=s[m][0].length();
            m++;
        }
    }

    for(int i=0;i<m;++i){
        for(int j=0;j<m;++j){
            for(int k=0;k<2;++k){
                for(int l=0;l<2;++l){
                    overlap[i][j][k][l]=Overlap(s[i][k],s[j][l]);
                }
            }
        }
    }
}

void update(int &x,int y){
    if(x==-1 || y<x)  x=y;
}

//这里使用刷表法进行状态转移
void Solve(){
    memset(dp,-1,(1<<m)*sizeof(dp[0]));
    dp[1][0][0]=len[0];
    int S=(1<<m);
    //因为是刷表法,s可以小于S-1
    for(int s=0;s<S-1;++s){
        for(int j=0;j<m;++j){
            for(int k=0;k<2;++k){
                if(dp[s][j][k]<0) continue;
                int t=dp[s][j][k];
                for(int i=0;i<m;++i){   //选择下一个字符串
                    if(s&(1<<i)) continue;
                    update(dp[s|(1<<i)][i][0],t+len[i]-overlap[j][i][k][0]);
                    update(dp[s|(1<<i)][i][1],t+len[i]-overlap[j][i][k][1]);
                }
            }
        }
    }
    int ans=-1;
    for(int i=0;i<m;++i){
        for(int k=0;k<2;++k){
            if(dp[S-1][i][k]==-1) continue;
            update(ans,dp[S-1][i][k]-overlap[i][0][k][0]);
        }
    }
    if(ans<=2) printf("2\n");
    else printf("%d\n",ans);
}

int main(void){
    while(cin>>n && n){
        Init();
        Solve();
    }
}
Published 15 original articles · won praise 0 · Views 174

Guess you like

Origin blog.csdn.net/zpf1998/article/details/103947024