• 【暑假】[深入动态规划]UVa 10618 Fun Game


    UVa 10618 Fun Game

    题目:

      http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=36035

    思路:

      一圈人围坐,给出小球的传递序列,求解最少有多少个人。

      问题简单化:如果有一排人,单向传递,给出序列求解最少多少人。那么问题就是:求解一个最短序列使得给出的所有序列都是该序列的连续子序列。

      再分别解决以下问题:

    1.     第一个人可以向左向右传递: 每个传递序列有两种情况,分别是正序与逆序。因为不清楚当前序列是向左传还是向右传。
    2.     传递是一个环:规定将第一个序列正向串作为首序列,累计答案的时候只需要算上重叠部分即可。
    3.     输入可能是绕过好几圈的情况:如果绕过好几圈,那么其他的字串因已经被包含而舍弃,dp过程不会进行,最后累计ans时ans=len[0]-重叠(s[0][0],s[0][0])即最小循环节的长度。
    4.     输入保证n>=2:当ans<=1是修改为2

    代码:

     

     1 #include<iostream>
     2 #include<cstring>
     3 #include<vector>
     4 #include<algorithm>
     5 #define FOR(a,b,c) for(int a=(b);a<(c);a++)
     6 using namespace std;
     7 
     8 const int maxn = 16;
     9 const int maxlen= 100 + 5;
    10 
    11 struct Node{
    12     string s,rev;
    13     bool operator <(const Node& rhs) const{
    14       return s.size()<rhs.s.size();      //size由小到大 
    15     }
    16 };
    17 
    18 int n;
    19 int d[1<<maxn][maxn][2];
    20 int overlap[maxn][maxn][2][2];
    21 string s[maxn][2];
    22 int len[maxn];
    23 
    24 //return a右 && b左的重叠部分 
    25 int make_overlap(const string& a,const string& b){
    26     int n1=a.size();
    27     int n2=b.size();
    28     FOR(i,1,n1) {    //找到最小重合点 即返回最大重合长度 
    29         if(n2 + i <= n1) continue;
    30         bool ok=true;
    31         for(int j=0;i+j<n1;j++) 
    32           if(a[i+j] != b[j]) { ok=false; break; }
    33         if(ok) return n1-i;
    34     } 
    35     return 0;  //无重合 
    36 }
    37 
    38 void init() {
    39     Node nodes[maxn];
    40     FOR(i,0,n) {
    41         cin>>nodes[i].s;
    42         nodes[i].rev=nodes[i].s;
    43         reverse(nodes[i].rev.begin(),nodes[i].rev.end());  //反转串 
    44     }
    45     
    46     sort(nodes,nodes+n);    //sort 
    47     int nn=0;     
    48     FOR(i,0,n) {
    49         bool need=true;
    50         FOR(j,i+1,n) 
    51          if(nodes[j].s.find(nodes[i].s) != string::npos ||
    52           nodes[j].rev.find(nodes[i].s) != string::npos){  //如果被包含则舍弃 
    53              need=false; break;
    54          }
    55         if(need) {
    56             s[nn][0]=nodes[i].s;
    57             s[nn][1]=nodes[i].rev;
    58             len[nn]=s[nn][0].size();
    59             nn++;
    60         }
    61     }
    62     n=nn;
    63     
    64     //构造重叠数组 
    65     FOR(i,0,n) FOR(x,0,2)
    66      FOR(j,0,n) FOR(y,0,2)
    67       overlap[i][j][x][y]=make_overlap(s[i][x],s[j][y]);
    68 }
    69 
    70 inline void update(int& x,int v) {
    71     if(x<0 || v<x) x=v;
    72 }
    73 
    74 void solve() {
    75     memset(d,-1,sizeof(d));
    76     d[1][0][0]=len[0];  //始终把s[0][0]放在首位 
    77     
    78     int full=1<<n;
    79     FOR(s,1,full) 
    80       FOR(i,0,n) FOR(x,0,2) if(d[s][i][x]>=0) //已求过集合中的枚举 
    81        FOR(j,1,n) if(!((1<<j) & s)) FOR(y,0,2)  //刷表更新的目标枚举 
    82         update(d[s|(1<<j)][j][y],  d[s][i][x] + len[j]-overlap[i][j][x][y]);
    83         
    84     int ans=-1; full--;
    85     FOR(i,0,n) FOR(x,0,2) { 
    86       if(d[full][i][x]<0) continue; 
    87       update(ans, d[full][i][x] - overlap[i][0][x][0]);  //ans累计 枚举尾字串并减去与第一个串的重叠部分 
    88     } 
    89     if(ans<=1) cout<<"2
    ";       //题目中明确给出 n>=2 
    90     else 
    91      cout<<ans<<"
    ";
    92 }
    93 int main(){
    94     while(cin>>n && n) {
    95         init();
    96         solve();
    97     }
    98     return 0;
    99 }
  • 相关阅读:
    设计模式 享元模式(池化技术)
    设计模式 混合模式(整体部分模式)
    设计模式 适配器模式
    Flex3示例、 安装 、注册码
    VS2010错误
    转载:glut.h 与 stdlib.h中 的exit()重定义问题的解决
    宿迁软件QQ群(109233721)
    百度地图 开发API接口啦
    Sublime Text 插件个人使用总结&推荐
    sublime text2 使用安装插件中文乱码问题解决
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4741879.html
Copyright © 2020-2023  润新知