IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> hdu3247 Resource Archiver(AC自动机上bfs预处理+dfs/状压dp解tsp问题) -> 正文阅读

[数据结构与算法]hdu3247 Resource Archiver(AC自动机上bfs预处理+dfs/状压dp解tsp问题)

http://acm.hdu.edu.cn/showproblem.php?pid=3247

  • 把所有的串挂到自动机上去,这样就能在自动机上跑最短路
  • 由于最短路长度为1所以改成bfs
  • 标记病毒串不能bfs经过
  • 这样就变成10个串,预处理出根到每个串结尾的距离,就是先构造出哪个串
  • 然后再从这个串开始跑其他串,只要状态把全部串都跑到即可(类似tsp,不过tsp最后要回来再花代价)
  • 由于给了10sdfs也能接受就暴力跑了2s过

(发现自己的自动机之前的没有trie图却过了hdu板子题,甚至这道题我对拍了网上其他题解存在不同输出但是都ac了,这题数据挺水的,重在理解)

中途想了一个资源串存在公共前缀的问题,bfs中是跑出了到前缀串的距离。但是dfs的时候只是单纯判断资源串有没有跑到这个情况是可以剪枝的。因为前缀串包含在串中,因此从结果来看选择前缀串来跑更优。所以dfs的进入可以判断一下当前串是不是已经在状态中了来剪一下枝头。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=6e4+5;
const int maxm=13;
typedef int LL;
typedef pair<LL,LL>P;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL tree[maxn][2],endp[maxn],fail[maxn],pc=0;
LL num[maxn],n,m;
LL dis[maxm][maxn];
LL ans=0x3f3f3f3f;
bool vis[maxn],has[maxm];
inline void ins(string& s,LL op,LL id){
     LL cur=0;
     for(int i=0;i<s.size();i++){
        LL c=s[i]-'0';
        if(!tree[cur][c]) tree[cur][c]=++pc;
        cur=tree[cur][c];
     }
     if(1==op){
        endp[cur]|=1<<(id-1);
        num[id]=cur;
     }
     else{
        endp[cur]=-1;
     }
}
///进行bfs处理以st为起点的最短路
inline void getfail(){
    queue<LL>que;
    fail[0]=0;
    for(int i=0;i<2;i++){
        if(tree[0][i]){
            fail[i]=0;que.push(tree[0][i]);
        }
    }
    while(!que.empty()){
        LL u=que.front();que.pop();
        if(endp[fail[u]]>=0) endp[u]|=endp[fail[u]];
        for(int i=0;i<2;i++){
            if(tree[u][i]){
                fail[tree[u][i]]=tree[fail[u]][i];
                que.push(tree[u][i]);
            }
            else{
                tree[u][i]=tree[fail[u]][i];
            }
        }
    }
}
inline void bfs(LL id,LL st){
    queue<P>que;
    que.push({st,0});
    dis[id][st]=0;
    memset(vis,0,sizeof(vis));
    while(!que.empty()){
        P p=que.front();que.pop();
        LL u=p.first;LL cost=p.second;
        if(endp[u]>0){
            dis[id][u]=cost;
        }
        for(int i=0;i<2;i++){
            LL v=tree[u][i];
            if(endp[v]==-1) continue;
            if(vis[v]) continue;
            vis[v]=true;
            que.push({v,cost+1});
        }
    }
}
///节点,状态,路径和
void dfs(LL now,LL state,LL val){
     if(state==(1<<n)-1) {
        ans=min(ans,val);return;
     }
     for(int i=1;i<=n;i++){
        ///||!(1<<(i-1)&state)资源串存在公共前缀,从短的到长的更优,不会重复加
        if(!has[i]){
            has[i]=true;
            dfs(i,state|(1<<(i-1)),val+dis[now][num[i]]);
            has[i]=false;
        }
     }
}
void init(){
     ans=0x3f3f3f3f;pc=0;
     memset(tree,0,sizeof(tree));
     memset(endp,0,sizeof(endp));
     memset(fail,0,sizeof(fail));
     memset(num,0,sizeof(num));
     memset(dis,0,sizeof(dis));
     memset(has,0,sizeof(has));
}
int main(void){

    while(~scanf("%d%d", &n, &m), n+m){
        for(int i=1;i<=n;i++){
            string s;cin>>s;
            ins(s,1,i);
        }
        for(int i=1;i<=m;i++){
            string s;cin>>s;
            ins(s,0,0);
        }
        getfail();
        num[0]=0;
        for(int i=0;i<=n;i++){
            bfs(i,num[i]);
        }
        for(int i=1;i<=n;i++){
            has[i]=true;
            dfs(i,endp[num[i]],dis[0][num[i]]);
            has[i]=false;
        }
        printf("%d\n",ans);
        init();
    }
   	return 0;
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-11-10 12:39:06  更:2021-11-10 12:39:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:31:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码