HDU 3247 Resource Archiver

給n個源串和m個病毒串,求包含所有源串但不包含任何病毒串的串的最短長度。利用源串和病毒串建立自動機,當爲源串時end記錄下標,病毒串時end標記爲-1,然後在跑bfs時如果當前節點的fail指向節點的end爲-1時,當前節點也需標記爲-1,否則end[p]|=end[fail[p]].然後用dp[i][j]跑狀壓dp,i表示當前包含串的狀態,j爲當前節點狀態,然後還需用一個二維數組表示mark[i][j]表示i節點是否能到j結點,但是是先把是病毒串尾串標記的節點去掉後的正常節點,然後用bfs跑出每個點到另外一個點的最短路,然後利用mark數組跑狀壓,最後最小的dp[(1<<n)-1][i]就是答案,i是去掉後的所有節點。代碼如下

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
const int INF=1e9;
const int MOD=20090717;

struct Tree
{
	int next[60010][2],end[60010],fail[60010];
	int L,root;
	int newnode()
	{
		for(int i=0;i<2;i++)
		{
			next[L][i]=-1;
		}
		end[L++]=0;
		return L-1;
	}
	void init()
	{
		L=0;
		root=newnode();
	}
	int getch(char ch)
	{
		if(ch=='0') return 0;
		else return 1;
	}
	void insert(char *s,int idx)
	{
		int len=strlen(s);
		int p=root;
		for(int i=0;i<len;i++)
		{
			int id=getch(s[i]);
			if(next[p][id]==-1)
			{
				next[p][id]=newnode();
			}
			p=next[p][id];
		}
		end[p]=idx;
	}
	void build()
	{
		queue<int>q;
		int p=root;
		fail[root]=root;
		for(int i=0;i<2;i++)
		{
		//	printf("%d %d %d\n",i,p,next[p][i]);
			if(next[p][i]==-1)
			{
				next[p][i]=root;
			}
			else
			{
				fail[next[p][i]]=root;
				q.push(next[p][i]);
			}
		}
		while(!q.empty())
		{
			p=q.front();
			q.pop();
			if(end[fail[p]]==-1) end[p]=-1;
			else end[p]|=end[fail[p]];
  			for(int i=0;i<2;i++)
			{
				if(next[p][i]==-1)
				{
					next[p][i]=next[fail[p]][i];
				}
				else
				{
					fail[next[p][i]]=next[fail[p]][i];
					q.push(next[p][i]);
				}
			}
		}
	}
	int pos[11],cnt;
	int g[11][11],dis[60010];
	int dp[2024][11];
	void bfs(int k)
	{
		memset(dis,-1,sizeof(dis));
		dis[pos[k]]=0;
		queue<int>q;
		q.push(pos[k]);
		while(!q.empty())
		{
			int p=q.front();
			q.pop();
			for(int i=0;i<2;i++)
			{
				int temp=next[p][i];
				if(dis[temp]<0&&end[temp]>=0)
				{
					dis[temp]=dis[p]+1;
					q.push(temp);
				}
			}
		}
		for(int i=0;i<cnt;i++)
		{
			g[k][i]=dis[pos[i]];
		}
	}
	void solve(int n)
	{
		pos[0]=0;
		cnt=1;
		for(int i=0;i<L;i++)
		{
			if(end[i]>0)
			pos[cnt++]=i;
		}
		for(int i=0;i<cnt;i++)
		{
			bfs(i);
		}
		for(int i=0;i<(1<<n);i++)
		{
			for(int j=0;j<cnt;j++)
			{
				dp[i][j]=INF;
			}
		}
		dp[0][0]=0;
		for(int i=0;i<(1<<n);i++)
		{
			for(int j=0;j<cnt;j++)
			{
				if(dp[i][j]<INF)
				for(int k=0;k<cnt;k++)
				{
					if(g[j][k]<0) continue;
					if(j==k) continue;
 					int s=end[pos[k]];
					dp[i|s][k]=min(dp[i|s][k],dp[i][j]+g[j][k]);
				}
			}
		}
		int ans=INF;
		for(int i=0;i<cnt;i++)
		{
			ans=min(ans,dp[(1<<n)-1][i]);
		}
		printf("%d\n",ans);
	}
	/*void query(char *s)
	{
		int len=strlen(s);
		int p=root,ans=0;
		memset(cnt,0,sizeof(cnt));
		memset(last,-1,sizeof(last));
		for(int i=0;i<len;i++)
		{
			int id=s[i]-'a';
			p=next[p][id];
			int temp=p;
			while(temp!=root)
			{
				cnt[0][temp]++;
				if(i-last[temp]>=deep[temp])
				{
					cnt[1][temp]++;
					last[temp]=i;
				}
				temp=fail[temp];
			}
		}
	}*/
/*	void debug()
    {
        for(int i = 0;i < L;i++)
        {
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
            for(int j = 0;j < 26;j++)
                printf("%2d",next[i][j]);
            printf("]\n");
        }
    }*/
};
Tree ac;
char s[1010];
int main()
{
	int n,m;
	while(~scanf("%d %d",&n,&m))
	{
		if(n==0&&m==0) break;
		ac.init();
		for(int i=0;i<n;i++)
		{
			scanf("%s",s);
			ac.insert(s,(1<<i));
		}
		for(int i=0;i<m;i++)
		{
			scanf("%s",s);
			ac.insert(s,-1);
		}
		ac.build();
		ac.solve(n);
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章