zoukankan      html  css  js  c++  java
  • 【LOJ#3026】管道监控

    题目

    题目链接:https://loj.ac/p/3026

    (nleq 500,mleq 10^5,sum |s_i|leq 10^6)

    思路

    我们可以把字符串倒着插入一棵 Trie,然后枚举给出的树上的所有点 (x),同时在这个节点和 Trie 树上跳。如果当前跳到点 (y),此时 Trie 树上跳到的点恰好是某一个字符串的结尾,那么我们就从 (y)(x) 连一条流量为 (1),费用为匹配的字符串的代价的边。
    然后我们设点 (i) 子树内有 (f_i) 个叶子,那么就从 (i) 的父亲向 (i) 连一条流量为 (f_i),费用为 (0) 的边,同时从 (i)(i) 的父亲连一条流量为 (+infty),费用为 (0) 的边。
    最后从源点向 (1) 连流量为 (+infty),费用为 (0) 的边,每一个叶子向汇点连流量为 (1),费用为 (0) 的边,跑最小费用最大流即可。
    这个思路和昨天比赛志愿者招募是几乎一样的。不再赘述。

    代码

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    typedef long long ll;
    
    const int N=510,M=1000010;
    const ll Inf=1e18;
    int n,m,t,S,T,tot=1,head[N],fa[N],flw[N],pre[N];
    ll cost,maxf,dis[N];
    char s[M],c[N];
    bool vis[N];
    
    struct edge
    {
    	int next,to,flow,cost,id;
    }e[M];
    
    void add(int from,int to,int flow,int cost,int id=0)
    {
    	e[++tot]=(edge){head[from],to,flow,cost,id};
    	head[from]=tot;
    	swap(from,to);
    	e[++tot]=(edge){head[from],to,0,-cost,id};
    	head[from]=tot;
    }
    
    struct Trie
    {
    	int tot,ch[M][26],cost[M],id[M];
    	Trie() { memset(cost,0x3f3f3f3f,sizeof(cost)); tot=1; }
    	
    	void ins(char *s,int val,int k)
    	{
    		int p=1,len=strlen(s+1);
    		for (int i=len;i>=1;i--)
    		{
    			if (!ch[p][s[i]-'a']) ch[p][s[i]-'a']=++tot;
    			p=ch[p][s[i]-'a'];
    		}
    		if (val<cost[p]) cost[p]=val,id[p]=k;
    	}
    	
    	void addedge(int x)
    	{
    		int p=1;
    		for (int y=x;fa[y];y=fa[y])
    		{
    			if (!ch[p][c[y]-'a']) break;
    			p=ch[p][c[y]-'a'];
    			if (cost[p]<Inf) add(fa[y],x,1,cost[p],id[p]);
    		}
    	}
    }trie;
    
    bool spfa()
    {
    	memset(dis,0x3f3f3f3f,sizeof(dis));
    	deque<int> q;
    	q.push_back(S); dis[S]=0;
    	while (q.size())
    	{
    		int u=q.front(); q.pop_front();
    		vis[u]=0;
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (e[i].flow && dis[v]>dis[u]+e[i].cost)
    			{
    				dis[v]=dis[u]+e[i].cost; pre[v]=i;
    				if (!vis[v])
    				{
    					vis[v]=1;
    					if (q.size() && dis[v]<=dis[q.front()]) q.push_front(v);
    						else q.push_back(v);
    				}
    			}
    		}
    	}
    	return dis[T]<Inf;
    }
    
    void addflow()
    {
    	int minf=Inf;
    	for (int i=T;i!=S;i=e[pre[i]^1].to)
    		minf=min(minf,e[pre[i]].flow);
    	for (int i=T;i!=S;i=e[pre[i]^1].to)
    		e[pre[i]].flow-=minf,e[pre[i]^1].flow+=minf;
    	cost+=dis[T]*minf; maxf-=minf;
    }
    
    void MCMF()
    {
    	while (spfa()) addflow();
    }
    
    signed main()
    {
    	memset(head,-1,sizeof(head));
    	S=N-1; T=N-2;
    	scanf("%lld%lld%lld",&n,&m,&t);
    	for (int i=2;i<=n;i++)
    	{
    		scanf("%lld",&fa[i]);
    		while (c[i]=getchar())
    			if (c[i]>='a' && c[i]<='z') break;
    		flw[i]=1; flw[fa[i]]=0;
    	}
    	add(S,1,Inf,0);
    	for (int i=1;i<=n;i++)
    		if (flw[i]) add(i,T,1,0),maxf++;
    	for (int i=n;i>=1;i--)
    	{
    		add(fa[i],i,flw[i]-1,0);
    		add(i,fa[i],Inf,0);
    		flw[fa[i]]+=flw[i];
    	}
    	for (int i=1,x;i<=m;i++)
    	{
    		scanf("%lld%s",&x,s+1);
    		trie.ins(s,x,i);
    	}
    	for (int i=1;i<=n;i++)
    		trie.addedge(i);
    	MCMF();
    	if (maxf) return printf("-1"),0;
    	cout<<cost<<"
    ";
    	if (t)
    	{
    		cost=0;
    		for (int i=2;i<=tot;i+=2)
    			if (!e[i].flow && e[i].id) cost++;
    		cout<<cost<<"
    ";
    		for (int i=2;i<=tot;i+=2)
    			if (!e[i].flow && e[i].id)
    				cout<<e[i^1].to<<" "<<e[i].to<<" "<<e[i].id<<"
    ";
    	}
    	return 0;
    }
    
  • 相关阅读:
    Insus Meta Utility
    The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.
    Insus Binary Utility
    asp.net实现文件下载功能
    Column 'Column Name' does not belong to table Table
    程序已被编译为DLL,怎样去修改程序功能
    如何在Web网站实现搜索功能
    如何把数据流转换为二进制字符串
    Asp.net更新文件夹的文件
    如何显示中文月份
  • 原文地址:https://www.cnblogs.com/stoorz/p/15024640.html
Copyright © 2011-2022 走看看