• 题解【LOJ10082】「一本通 3.3 例 1」Word Rings


    题面

    一开始有一个很直观的想法:

    对于每一个单词,如果它能够与另外一个单词相匹配,就从当前单词向另外一个单词连一条长度为当前单词长度的边。

    但这样做最坏情况下会有 (10^5) 个点,(10^{10}) 条边,时间和空间都会承受不了。

    于是我们考虑如何优化建图。

    换一种建图的方式:

    对于每一个单词,将它的前两个字符和后两个字符之间连一条长度为当前单词的长度的边。

    稍微思考一下就会发现这种建图方式其实是和第一种等价的。

    建完图后,这个问题就变成了一个 (01) 分数规划问题,要求的是 (frac{sum 单词长度总和}{sum 单词个数}) 的最大值。

    然后就是一些基本操作:二分答案 (+) SPFA 找 正环

    注意 SPFA 时需要加一些优化:

    • 记录一下进行过松弛操作的点的数量,如果所有的点都已经做过了,就说明很大可能存在一个正环,直接返回 true;

    这样就可以通过此题了。

     #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 703, M = 200003;
    
    int n, m;
    int tot, head[N], ver[M], nxt[M], edge[M];
    double dist[N];
    int cnt[N];
    bool st[N];
    char s[1003];
    
    inline void add(int u, int v, int w)
    {
        ver[++tot] = v, edge[tot] = w, nxt[tot] = head[u], head[u] = tot;
    }
    
    inline bool check(double mid)
    {
        memset(cnt, 0, sizeof cnt);
        memset(st, false, sizeof st);
        queue <int> q;
        for (int i = 0; i <= 675; i+=1)
        {
            q.push(i); //先将所有点加进队列
            st[i] = true;
        }
        int cntt = 0;
        while (!q.empty())
        {
            int u = q.front(); q.pop();
            st[u] = false;
            for (int i = head[u]; i; i = nxt[i])
            {
                int v = ver[i], w = edge[i];
                if (dist[v] < dist[u] + w - mid)
                {
                    dist[v] = dist[u] + w - mid;
                    cnt[v] = cnt[u] + 1;
                    if (++cntt > 10000) return true; //进行过松弛操作的点的数量
                    if (cnt[v] >= N) return true; //存在正环
                    if (!st[v])
                    {
                        st[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        return false; //没有正环
    }
    
    int main()
    {
        while (1)
        {
            cin >> n;
            if (!n) break;
            memset(head, 0, sizeof head);
            tot = 0;
            for (int i = 1; i <= n; i+=1)
            {
                scanf("%s", s + 1);
                int len = strlen(s + 1);
                if (len >= 2)
                {
                    int c1 = (s[1] - 'a') * 26 + (s[2] - 'a'), c2 = (s[len - 1] - 'a') * 26 + (s[len] - 'a');
                    add(c1, c2, len); //建图,注意是单向边
                }
            }
            if (!check(0)) {puts("No solution"); continue;}
            double l = 0.0, r = 1003.0;
            while (r - l > 1e-4)
            {
                double mid = (l + r) / 2.0;
                if (check(mid)) l = mid;
                else r = mid;
            }
            printf("%.2lf
    ", l);
        }
        return 0;
    }
    
  • 相关阅读:
    poj 2488 DFS
    畅通工程 并查集模版
    KMP 模板
    poj 1426 DFS
    poj 2528 线段数
    poj 3468 线段数 修改区间(点)
    CVPR2012文章阅读(2)A Unified Approach to Salient Object Detection via Low Rank Matrix Recovery
    如何制定目标
    Saliency Map 最新综述
    计算机视觉模式识别重要会议杂志
  • 原文地址:https://www.cnblogs.com/xsl19/p/12402655.html
Copyright © 2020-2023  润新知