-
Notifications
You must be signed in to change notification settings - Fork 59
/
Copy pathdep.cpp
123 lines (104 loc) · 3.26 KB
/
dep.cpp
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# include <cstdio>
# include <vector>
# include <cstring>
# define NR 305
# define MOD 666013
using namespace std;
vector <int> v[NR], vt[NR], V[NR];
int i,j,n,m,x,y,CompTareConexa,a,b,c,VV,K,k,S;
int drum[NR][NR], ap[NR], st[NR], CTC[NR], noduri[NR], radacina[NR];
long long DP[NR][NR], nou[NR], Solutie[NR];
void DFS (int k)
{
ap[k]=1;
for (int i=0; i<v[k].size(); ++i)
if (! ap[v[k][i]]) DFS (v[k][i]);
st[++VV]=k;
}
void DFSt (int k)
{
ap[k]=1; CTC[k]=CompTareConexa; ++noduri[CompTareConexa];
for (int i=0; i<vt[k].size(); ++i)
if (! ap[vt[k][i]]) DFSt (vt[k][i]);
}
void uneste (int x, int y) //x e radacina
{
memset (nou, 0, sizeof(nou));
for (int i=0; i<=K; ++i)
for (int j=1; j<=K; ++j)
if (i+j<=K) nou[i+j]=nou[i+j] + DP[x][i]*DP[y][j];
for (int i=1; i<=K; ++i)
DP[x][i]=(DP[x][i] + nou[i])%MOD;
}
void Dinamica (int k)
{
//DP[i][j] - numarul de moduri de a alege j elemente unite de radacina indirect din nodul i
DP[k][noduri[k]]=1;
for (int i=0; i<V[k].size(); ++i) {
Dinamica (V[k][i]);
//trebuie sa unesc noua solutie cu precedentele
uneste (k, V[k][i]);
}
}
int main ()
{
freopen ("dep.in", "r", stdin);
freopen ("dep.out", "w", stdout);
scanf ("%d%d%d", &n, &m, &K);
for (i=1; i<=m; ++i) {
scanf ("%d%d", &x, &y);
v[x].push_back(y);
vt[y].push_back(x);
}
// incepem sa compactam componentele tare conexe
for (i=1; i<=n; ++i)
if (! ap[i]) DFS (i);
memset (ap, 0, sizeof(ap));
for (i=n; i>=1; --i)
if (! ap[st[i]]) {
++CompTareConexa;
DFSt (st[i]);
}
//fac noul graf compactat
for (i=1; i<=n; ++i)
for (j=0; j<v[i].size(); ++j)
if (CTC[i]!=CTC[v[i][j]]) drum[CTC[i]][CTC[v[i][j]]]=1;
//facem toate conexiunile indirecte
for (k=1; k<=CompTareConexa; ++k)
for (i=1; i<=CompTareConexa; ++i)
for (j=1; j<=CompTareConexa; ++j)
if (i!=j && drum[i][k] && drum[k][j]) drum[i][j]=1;
//scapam de muchie in plus
for (a=1; a<=CompTareConexa; ++a)
for (b=1; b<=CompTareConexa; ++b)
for (c=1; c<=CompTareConexa; ++c)
if (drum[a][b] && drum[a][c]) {
if (drum[b][c]) drum[a][c]=0;
else if (drum[c][b]) drum[a][b]=0;
}
//acum avem mai multi arbori orientati
// -> trebuie sa facem graful transpus, dupa care sa aplicam dinamica
for (i=1; i<=CompTareConexa; ++i) {
S=0;
for (j=1; j<=CompTareConexa; ++j)
if (drum[i][j]) {++S; V[j].push_back(i);}
if (S==0) radacina[i]=1;
}
//////////////////////////////////////////////////////////////////////////
//incepem dinamica
Solutie[0]=1;
for (i=1; i<=CompTareConexa; ++i)
if (radacina[i])
{
Dinamica (i);
//unim si solutiile dintre arbori diferiti
memset (nou, 0, sizeof(nou));
for (int o=0; o<=K; ++o)
for (int j=1; j<=K; ++j)
if (o+j<=K) nou[o+j]=nou[o+j] + Solutie[o]*DP[i][j];
for (int o=1; o<=K; ++o)
Solutie[o]=(Solutie[o] + nou[o])%MOD;
}
printf ("%d\n", Solutie[K]);
return 0;
}