「成都七中D5T2」第二题 - 动态规划 | Bill Yang's Blog

「成都七中D5T2」第二题 - 动态规划

题目大意

    这是第二题,仍然是一道送分题。
    给出了一个$N$个点$M$条边的有向图。
    求有多少个有序点对$(a,b)$,满足至少存在一个点$c$以及从$c$到$a$的一条路径$L_a$,$c$到$b$的一条路径$L_b$,使得$L_a$的长度是$L_b$的两倍(长度指的经过的边的数目)
    注意不一定是简单路径。

题目分析

输出$n\times n$,爆零。。。

类似的一道题,我们通过确定搜索图的状态进行动态规划。
不难发现,设$f[x,y]$表示从某个$c$出发,$a$在$x$,$b$在$y$时是否合法。

显然,我们有一个$O(nm^2)$的算法。
即枚举$x$的后继与$y$的二倍后继进行转移。

我们可以另设状态使转移分步。
设$f[i,j,k=0/1/2]$分别表示当前状态为$(i,j)$,轮到$i$走($0$),轮到$j$走($1/2$)是否合法。
$k=0/1/2$只能转移到$(k+1)\bmod\,3$。

在$k=0$时统计答案

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<climits>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

const int maxn=3005;

vector<int>edges[maxn];

void AddEdge(int x,int y) {
edges[x].push_back(y);
}

struct QueNode {
int x,y,t;
QueNode(int _x=0,int _y=0,int _t=0):x(_x),y(_y),t(_t) {}
};

queue<QueNode>Q;

int n,m,ans;
bool vst[maxn][maxn][3];

int main() {
n=Get_Int();
m=Get_Int();
for(int i=1; i<=m; i++) {
int x=Get_Int(),y=Get_Int();
AddEdge(x,y);
}
for(int i=1; i<=n; i++)vst[i][i][0]=1,Q.push(QueNode(i,i,0));
ans=n;
while(!Q.empty()) {
QueNode Now=Q.front();
int x=Now.x,y=Now.y,t=Now.t;
Q.pop();
if(t==0) {
for(int Next:edges[x]) {
if(vst[Next][y][1])continue;
vst[Next][y][1]=1;
Q.push(QueNode(Next,y,1));
}
} else {
int nextt=(t+1)%3;
for(int Next:edges[y]) {
if(vst[x][Next][nextt])continue;
vst[x][Next][nextt]=1;
if(nextt==0)ans++;
Q.push(QueNode(x,Next,nextt));
}
}
}
printf("%d\n",ans);
return 0;
}
姥爷们赏瓶冰阔落吧~
0%