hdoj 5457 Hold Your Hand 【字典树 + 最小割】



Hold Your Hand

Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 203    Accepted Submission(s): 53


Problem Description
She walks in beauty, like the night of cloudless climes and starry skies. And all that's best of dark and bright, meet in her aspect and her eyes. Thus mellow'd to that tender light, which heaven to gaudy day denies. Fang Fang says she is afraid of dark.

``Never fear, I will hold your hand," I reply.

Fang Fang says she hates some  8 -digit binary numbers.
I ask Cupid for help. Cupid can sell me some supernatural powers.
Some of them can eliminate all  8 -digit binary numbers in the world with a certain prefix, and some of them can eliminate all  8 -dight binary numbers with a certain suffix.

``..., but you must offer your IQ in exchange for them."

``You have my permission", I say. True, I should minimize my damage, but maybe you can help me.
 

Input
The input contains several test cases. The first line of the input is a single integer  t (t10)  which is the number of test cases.

Then  t  test cases follow.
Each test case contains several lines.
The first line contains the integer  n (1n256)  and  m (1m500) .
Here,  n  corresponds to the number of  8 -digit binary numbers which Fang Fang hates, and  m  corresponds to the number of supernatural powers.
The second line contains  n  integer numbers  a1,a2,,an  where  0a1,,an255 , which are  8 -digit binary numbers written by decimal representation.
The following  m  lines describe the supernatural powers one per line in two formats.
  P s w : you can eliminate all  8 -digit binary numbers by prefixing the string  s , with  w (1w1000)  units of IQ.
  S s w : you can eliminate all  8 -digit binary numbers by suffixing the string  s , with  w (1w1000)  units of IQ.
 

Output
For each test case, you should output the minimum cost of IQ as a unit, or ``-1" if Cupid could not help me.
 

Sample Input
      
      
1 8 7 0 1 2 3 4 5 6 7 P 000001 1 P 0000000 1 S 10 1 S 11 1 S 00 1 S 01 1 P 0000001 3
 

Sample Output
      
      
Case #1: 4
 



题意:给你n个数(大于0且小于256)和m个二进制串,每个串代表一个二进制的前缀(或者后缀)且具有一定的权值。如果一个数的二进制是这m个字符串中某一个的前缀(或者后缀),我们可以利用这个前缀(或者后缀)来消去这个数,代价就是该串的权值。现在问你能否利用给出的m个二进制串消去所有的数,若可以则输出消去所有数的最小代价,否则输出-1。



思路:利用前缀和后缀建立字典树,可以选择建两个字典树,也可以建立一个字典树。方法就是用该字典树的根的两个儿子节点S和T当做两个新字典树的根。然后把m个串以及每个数字的前缀、后缀插入到树里面,并记录串的权值。


建图:

连接字典树上所有叶子,权值为INF;

在S字典树上由上一节点->下一节点建边,权值为下一节点的权值;

在T字典树上由下一节点->上一节点建边,权值为下一节点的权值。

最后S->T跑一次最大流求出最小割就可以了。




AC代码:


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#define MAXN 10000+10
#define MAXM 2000000+100
#define INF 0x3f3f3f3f
using namespace std;
int S, T;//源点 汇点
struct MAXFLOW
{
    struct Edge{
        int from, to, cap, flow, next;
    };
    Edge edge[MAXM];
    int head[MAXN], edgenum;
    int dist[MAXN], cur[MAXN];
    bool vis[MAXN];
    void init(){
        edgenum = 0;
        memset(head, -1, sizeof(head));
    }
    void addEdge(int u, int v, int w)
    {
        Edge E1 = {u, v, w, 0, head[u]};
        edge[edgenum] = E1;
        head[u] = edgenum++;
        Edge E2 = {v, u, 0, 0, head[v]};
        edge[edgenum] = E2;
        head[v] = edgenum++;
    }
    bool BFS(int s, int t)
    {
        queue<int> Q;
        memset(dist, -1, sizeof(dist));
        memset(vis, false, sizeof(vis));
        dist[s] = 0, vis[s] = true;
        Q.push(s);
        while(!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            for(int i = head[u]; i != -1; i = edge[i].next)
            {
                Edge E = edge[i];
                if(!vis[E.to] && E.cap > E.flow)
                {
                    dist[E.to] = dist[u] + 1;
                    if(E.to == t) return true;
                    vis[E.to] = true;
                    Q.push(E.to);
                }
            }
        }
        return false;
    }
    int DFS(int x, int a, int t)
    {
        if(x == t || a == 0) return a;
        int flow = 0, f;
        for(int &i = cur[x]; i != -1; i = edge[i].next)
        {
            Edge &E = edge[i];
            if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap-E.flow), t)) > 0)
            {
                edge[i].flow += f;
                edge[i^1].flow -= f;
                flow += f;
                a -= f;
                if(a == 0) break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        int flow = 0;
        while(BFS(s, t))
        {
            memcpy(cur, head, sizeof(head));
            flow += DFS(s, INF, t);
        }
        return flow;
    }
};
MAXFLOW dinic;

struct TRIE
{
    int ch[MAXN][2];
    int val[MAXN];
    int sz;
    void init(){
        sz = 0;
    }
    int newnode(){
        int node = ++sz;
        memset(ch[node], 0, sizeof(ch[node]));
        val[node] = INF;
        return node;
    }
    int Insert(int root, char *s, int cost)
    {
        int u = root;
        for(int i = 0; s[i]; i++)
        {
            int v = s[i] - '0';
            if(!ch[u][v])
                ch[u][v] = newnode();
            u = ch[u][v];
        }
        val[u] = min(val[u], cost);
        return u;//返回串 结点
    }
    void DFS(int kind, int u)
    {
        for(int i = 0; i < 2; i++)
        {
            int v = ch[u][i];
            if(v)
            {
               if(kind == 1)
                    dinic.addEdge(u, v, val[v]);
               else
                    dinic.addEdge(v, u, val[v]);
                DFS(kind, v);
            }
        }
    }
};
TRIE trie;
int main()
{
    int t, k = 1;
    int n, m;
    int a[256+1]; char str[10];
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        char op[3]; int v;
        trie.init();
        S = trie.newnode(); T = trie.newnode();//源 汇为根的两个儿子
        for(int i = 0; i < m; i++)
        {
            scanf("%s%s%d", op, str, &v);
            if(op[0] == 'P')
                trie.Insert(S, str, v);
            else
            {
                strrev(str);
                trie.Insert(T, str, v);
            }
        }
        dinic.init();
        for(int i = 0; i < n; i++)
        {
            str[8] = '\0';
            for(int j = 0; j < 8; j++)
            {
                str[j] = (a[i] & 1) + '0';
                a[i] >>= 1;
            }
            int v = trie.Insert(T, str, INF);//T儿子 下属的节点
            strrev(str);
            int u = trie.Insert(S, str, INF);//S儿子 下属的节点
            dinic.addEdge(u, v, INF);
        }
        //S儿子建边
        trie.DFS(1, S);
        //T儿子建边
        trie.DFS(2, T);
        int ans = dinic.Maxflow(S, T);
        printf("Case #%d: ", k++);
        if(ans >= INF)
            printf("-1\n");
        else
            printf("%d\n", ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值