zoukankan      html  css  js  c++  java
  • HDU 1964 Pipes (插头DP,变形)

    题意:给一个n*m的矩阵,每个格子都是必走的,且无障碍格子,每对格子之间都有一个花费,问哈密顿回路的最小花费。

    思路:

      这个和Formula1差不多,只是求得是最小花费,这只需要修改一下DP值为花费就行了,主要是在创建新括号,以及延续一个插头的时候花费,因为可能上一个格子有多个状态都可以转移到本格子的同一状态,那么同一个格子中的同一状态的DP值取最小值即可。

      1 #include <bits/stdc++.h>
      2 #include <iostream>
      3 #include <cstdio>
      4 #include <cstring>
      5 #define pii pair<int,int>
      6 #define INF 0x3f3f3f3f
      7 #define LL long long
      8 using namespace std;
      9 const int N=105;
     10 
     11 int g[N][N], cur, n, m;
     12 struct Hash_Map
     13 {
     14     static const int mod=12357;
     15     static const int NN=100010;
     16     int head[mod];      //桶指针
     17     int next[NN];        //记录链的信息
     18     LL  status[NN];      //状态
     19     LL  value[NN];       //状态对应的DP值。
     20     int size;
     21 
     22     void clear()    //清除哈希表中的状态
     23     {
     24         memset(head, -1, sizeof(head));
     25         size = 0;
     26     }
     27 
     28     void insert(LL st, LL val)  //插入状态st的值为val
     29     {
     30         int h = st%mod;
     31         for(int i=head[h]; ~i; i=next[i])
     32             if(status[i] == st) //这个状态已经存在,累加进去。
     33             {
     34                 value[i] = min(value[i], val);
     35                 return ;
     36             }
     37         status[size]= st;           //找不到状态st,则插入st。
     38         value[size] = val;
     39         next[size] = head[h] ;      //新插入的元素在队头
     40         head[h] = size++;
     41     }
     42 }hashmap[2];
     43 
     44 inline int getbit(LL s,int pos)   //取出状态s的第pos个插头
     45 {
     46     return (s>>2*pos)&3;
     47 }
     48 inline int setbit(LL s,int pos,int bit)   //将状态s的第pos个插头设置为bit
     49 {
     50     if(s&(1<<2*pos ))     s^=1<<(2*pos);
     51     if(s&(1<<(2*pos+1)))  s^=1<<(2*pos+1);
     52     return (s|(bit<<2*pos));
     53 }
     54 
     55 int Fr(LL s,int pos,int bit)   //寻找状态s的第pos个插头对应的右括号。
     56 {
     57     int cnt=0;
     58     for(pos+=2; pos<m; pos++)
     59     {
     60         if(getbit(s, pos)==3-bit)   cnt++;
     61         if(getbit(s, pos)==bit)     cnt--;
     62         if(cnt==-1)         return setbit(s, pos, 3-bit);
     63     }
     64 }
     65 int Fl(LL s,int pos,int bit)   //寻找状态s的第pos个插头对应的左括号。
     66 {
     67     int cnt=0;
     68     for(pos--; pos>=0; pos--)
     69     {
     70         if(getbit(s, pos)==3-bit)  cnt++;
     71         if(getbit(s, pos)==bit)    cnt--;
     72         if( cnt==-1)    return setbit(s, pos, 3-bit);
     73     }
     74 }
     75 
     76 void DP(int i,int j)
     77 {
     78     LL t;
     79     for(int k=0; k<hashmap[cur^1].size; k++)
     80     {
     81         LL s=hashmap[cur^1].status[k];
     82         LL v=hashmap[cur^1].value[k];
     83         int R=getbit(s, j), D=getbit(s, j+1);
     84         if(R && D)  //两个括号
     85         {
     86             t=(setbit(s,j,0)&setbit(s,j+1,0));
     87             if(R==D)    //同个方向的括号
     88             {
     89                 if(R==1)    t=Fr(t, j, 2);  //要改
     90                 else        t=Fl(t, j, 1);
     91                 hashmap[cur].insert(t, v);
     92             }
     93             else if( R==2 && D==1 )        //不同的连通分量
     94                 hashmap[cur].insert(t, v);
     95             else if( i+1==n && j+1==m && t==0 )        //终点才能闭合
     96                 hashmap[cur].insert(t, v);
     97         }
     98         else if(R || D)     //仅1个括号
     99         {
    100             if(R)   //右插头
    101             {
    102                 if(i+1<n )   hashmap[cur].insert(s, v+g[i*m+j+1][i*m+m+j+1]);//往下
    103                 if(j+1<m )   hashmap[cur].insert(setbit(setbit(s,j,0), j+1, R), v+g[i*m+j+1][i*m+j+2]);//往右
    104             }
    105             else    //下插头
    106             {
    107                 if(j+1<m )   hashmap[cur].insert(s, v+g[i*m+j+1][i*m+j+2]); //往右
    108                 if(i+1<n )   hashmap[cur].insert(setbit(setbit(s,j+1,0), j, D), v+g[i*m+j+1][i*m+m+j+1]);//往下
    109             }
    110         }
    111         else                //无括号
    112         {
    113             if(  j+1<m && i+1<n )    //新括号
    114             {
    115                 v+=g[i*m+j+1][i*m+m+j+1];   //
    116                 v+=g[i*m+j+1][i*m+j+2];     //
    117                 hashmap[cur].insert( setbit(s,j,1)|setbit(s,j+1,2), v);
    118             }
    119         }
    120     }
    121 }
    122 
    123 void cal()
    124 {
    125     for(int i=0; i<n; i++)
    126     {
    127         cur^=1;
    128         hashmap[cur].clear();
    129         for(int j=0; j<hashmap[cur^1].size; j++)    //新行,需要左移一下状态。
    130             hashmap[cur].insert( hashmap[cur^1].status[j]<<2, hashmap[cur^1].value[j] );
    131         for(int j=0; j<m; j++)
    132         {
    133             cur^=1;
    134             hashmap[cur].clear();
    135             DP(i,j);
    136         }
    137     }
    138 }
    139 LL print()
    140 {
    141     for(int i=0; i<hashmap[cur].size; i++)
    142         if(hashmap[cur].status[i]==0)
    143             return hashmap[cur].value[i];
    144     return 0;
    145 }
    146 
    147 
    148 int main()
    149 {
    150     //freopen("input.txt", "r", stdin);
    151     int t, Case=0;
    152     cin>>t;
    153     while(t--)
    154     {
    155         memset(g,0,sizeof(g));
    156         n=m=cur=0;
    157         scanf("%d%d",&n,&m);
    158         for(int i=1; i<n; i++)      //输入
    159         {
    160             for(int j=1; j<m; j++)  //左右
    161             {
    162                 char c=getchar();
    163                 if(isdigit(c))
    164                     g[i*m-m+j][i*m-m+j+1]=g[i*m-m+j+1][i*m-m+j]=c-'0';
    165                 else j--;
    166             }
    167             for(int j=1; j<=m; j++) //上下
    168             {
    169                 char c=getchar();
    170                 if(isdigit(c))
    171                     g[i*m-m+j][i*m+j]=g[i*m+j][i*m-m+j]=c-'0';
    172                 else j--;
    173             }
    174         }
    175         for(int j=1; j<m; j++)      //最后一行:左右
    176         {
    177             char c=getchar();
    178             if(isdigit(c))
    179                 g[n*m-m+j][n*m-m+j+1]=g[n*m-m+j+1][n*m-m+j]=c-'0';
    180             else j--;
    181         }
    182         char s[20];
    183         scanf("%s%s",s,s);//多余
    184 
    185         hashmap[cur].clear();
    186         hashmap[cur].insert(0, 0);  //初始状态:花费0
    187         cal();
    188         cout<<print()<<endl;
    189     }
    190     return 0;
    191 }
    AC代码
  • 相关阅读:
    Maven简介
    Activiti核心API
    Activiti数据库支持
    使用idea进行activiti工作流开发入门学习
    Activiti 工作流
    枚举其他用法
    枚举类的基本使用
    kotlin中抽象类
    kotlin中接口
    kotlin 类的继承
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4790107.html
Copyright © 2011-2022 走看看