首页 > 其他 > 详细

9.17 第二题

时间:2019-09-17 22:06:42      阅读:140      评论:0      收藏:0      [点我收藏+]

题意

给出了一个\(N\)个点\(M\)条边的有向图
求有多少个有序点对\((a,b)\),满足至少存在一个点\(c\)以及从\(c\)\(a\)的一条路径\(L_a\)\(c\)
\(b\) 的一条路径\(L_b\),使得\(L_a\)的长度是\(L_b\)的两倍
注意不一定是简单路径

\(N,M\leq 3\times10^3\)


解法

考虑对于点\(c\),一个合法的二元组是怎样形成的

我们可以看成是由点\(a,b\)\(c\)开始,点\(a\)走一步,点\(b\)走两步这样不断行走而形成的

我们把这个过程拆成三个阶段:

  • \(a\)向其出边走一步
  • \(b\)向其出边走一步
  • \(b\)向其出边走一步

对于任意一组合法的方案我们进行上述操作,一定都能得到一组新的合法的方案

我们考虑记忆化搜索

\(f[a][b][0]\)为合法状态,\(f[a][b][1]\)为第一阶段的状态,\(f[a][b][2]\)为第二阶段的状态。当到达第三阶段时,我们又获得一个合法状态,于是又用\(f[a][b][0]\)存储

考虑记忆化搜索的方式,我们用广搜不断扩展合法状态,类似今年省选\(\tt {D2T1}\)校园路径

最后统计答案累加即可

一共只有\(3N^2\)个状态,所以最后的时间复杂度是\(O(3N^2)\)


代码

#include <cstdio>
#include <queue>

using namespace std;

const int N = 3010;

int read();

struct node { 
    int u, v, w; 
    node(int _u, int _v, int _w) : u(_u), v(_v), w(_w) {}
};

int n, m;

int cap;
int head[N], nxt[N], to[N];

int f[N][N][3];

queue<node> que;

inline void add(int x, int y) { 
    to[++cap] = y, nxt[cap] = head[x], head[x] = cap; 
}


int main() {
    
    n = read(), m = read(); 
    for (int i = 1; i <= m; ++i) {
        int x = read(), y = read();
        add(x, y);
    }
    
    for (int i = 1; i <= n; ++i)  que.push(node(i, i, 0));
    for (int i = 1; i <= n; ++i)  f[i][i][0] = 1;
    
    while (!que.empty()) {
        node top = que.front(); que.pop();
        int u = top.u, v = top.v, w = top.w;
        if (!w) {
            for (int i = head[u]; i; i = nxt[i])
                if (!f[to[i]][v][1])  
                    f[to[i]][v][1] = 1, que.push(node(to[i], v, 1));
        } else {
            w = (w + 1) % 3;
            for (int i = head[v]; i; i = nxt[i])
                if (!f[u][to[i]][w])    
                    f[u][to[i]][w] = 1, que.push(node(u, to[i], w));
        }
    }
    
    int ans = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            ans += f[i][j][0];
    
    printf("%d\n", ans);
    
    return 0;
}

int read() {
    int x = 0, c = getchar();
    while (c < '0' || c > '9')   c = getchar();
    while (c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
    return x;   
}

9.17 第二题

原文:https://www.cnblogs.com/VeniVidiVici/p/11537541.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!