Tarjan & LCA 套题题目题解
刷题之前来几套LCA的末班
对于题目
HDU 2586 How far away
2份在线模板第一份倍增,倍增还是比较好理解的
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int head[MAXN],tot;
int N; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} int dep[MAXN],fa[MAXN],cost[MAXN];
int sumcost[MAXN][],anc[MAXN][];
bool vis[MAXN]; void bfs(int root)
{
memset(vis,false,sizeof(vis));
queue<int>q;
q.push(root);
vis[root] = true;
fa[root] = -;
dep[root] = ;
cost[root] = ;
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (vis[v]) continue;
dep[v] = dep[u] + ;
cost[v] = edge[i].w;
fa[v] = u;
vis[v] = true;
q.push(v);
}
}
} void preprocess()
{
memset(sumcost,,sizeof(sumcost));
for (int i = ; i <= N ; i++)
{
anc[i][] = fa[i];
sumcost[i][] = cost[i];
for (int j = ; ( << j) <= N ; j++) anc[i][j] = -;
}
for (int j = ; ( << j) <= N ; j++)
{
for (int i = ; i <= N ; i++)
{
if (anc[i][j - ] != -)
{
int a = anc[i][j - ];
anc[i][j] = anc[a][j - ];
sumcost[i][j] = sumcost[i][j - ] + sumcost[a][j - ];
}
}
}
} int query(int p,int q)
{
int tmp,log;
if (dep[p] < dep[q]) swap(p,q);
for (log = ; ( << log) <= dep[p] ; log++); log--;
int ans = ;
for (int i = log ; i >= ; i--)
{
if (dep[p] - ( << i) >= dep[q])
{
ans += sumcost[p][i];
p = anc[p][i];
}
}
if (p == q) return ans;
for (int i = log ; i >= ; i--)
{
if (anc[p][i] != - && anc[p][i] != anc[q][i])
{
ans += sumcost[p][i]; p = anc[p][i];
ans += sumcost[q][i]; q = anc[q][i];
}
}
ans += cost[p];
ans += cost[q];
return ans;
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
init();
int Q;
scanf("%d%d",&N,&Q);
for (int i = ; i < N - ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
bfs();
//printf("%d %d %d %d\n",fa[2],fa[3],cost[2],cost[3]);
preprocess();
//printf("%d %d %d %d\n",anc[2][0],anc[3][0],sumcost[2][0],sumcost[3][0]);
while(Q--)
{
int u,v;
scanf("%d%d",&u,&v);
printf("%d\n",query(u,v));
}
}
return ;
}
第二份DFS+ST+rmq。关于这种算法的解释在代码里有个链接
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
}edge[MAXN * ];
int head[MAXN],tol; void init()
{
memset(head,-,sizeof(head));
tol = ;
} void add_edge(int u,int v,int w)
{
edge[tol].u = u;
edge[tol].v = v;
edge[tol].w = w;
edge[tol].next = head[u];
head[u] = tol++;
} int ver[MAXN * ],R[MAXN * ],first[MAXN],dir[MAXN];
bool vis[MAXN];
int fac[];
int tot;
int dp[MAXN * ][]; void dfs(int u ,int dep)
{
vis[u] = true; ver[++tot] = u; first[u] = tot; R[tot] = dep;
for(int i = head[u]; i != - ; i=edge[i].next)
if( !vis[edge[i].v] )
{
int v = edge[i].v , w = edge[i].w;
dir[v] = dir[u] + w;
dfs(v,dep+);
ver[++tot] = u; R[tot] = dep;
}
} void ST(int len)
{
int K = (int)(log((double)len) / log(2.0));
for(int i = ; i <= len ; i++) dp[i][] = i;
for(int j = ; j <= K ; j++)
for(int i = ; i + fac[j] - <= len ; i++)
{
int a = dp[i][j - ] , b = dp[i + fac[j - ]][j - ];
if(R[a] < R[b]) dp[i][j] = a;
else dp[i][j] = b;
}
} int RMQ(int x ,int y)
{
int K = (int)(log((double)(y - x + )) / log(2.0));
int a = dp[x][K] , b = dp[y - fac[K] + ][K];
if(R[a] < R[b]) return a;
else return b;
} int LCA(int u ,int v)
{
int x = first[u] , y = first[v];
if(x > y) swap(x,y);
int res = RMQ(x,y);
return ver[res];
} int main()
{
for (int i = ; i < ; i++) fac[i] = ( << i);
int T;
scanf("%d",&T);
while (T--)
{
int N,Q;
init();
scanf("%d%d",&N,&Q);
memset(vis,false,sizeof(vis));
for (int i = ; i < N ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
tot = ;
dir[] = ;
dfs(,);
/*
printf("节点 "); for(int i=1; i<=2*N-1; i++) printf("%d ",ver[i]); cout << endl;
printf("深度 "); for(int i=1; i<=2*N-1; i++) printf("%d ",R[i]); cout << endl;
printf("首位 "); for(int i=0; i<=N; i++) printf("%d ",first[i]); cout << endl;
printf("距离 "); for(int i=0; i<=N; i++) printf("%d ",dir[i]); cout << endl;
*/
//以上四行表示了该模版的全部数组含义详细LCA RMQ在线分析在http://www.cnblogs.com/scau20110726/archive/2013/05/26/3100812.html
ST( * N - );
while (Q--)
{
int u,v;
scanf("%d%d",&u,&v);
int lca = LCA(u,v);
// printf("%d %d %d %d %d %d\n",u,v,dir[u],dir[v],lca,dir[lca]);
printf("%d\n",dir[u] + dir[v] - * dir[lca]);
}
}
return ;
}
HDU 1269 迷宫城堡
裸题+中文题!
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N,M;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN]; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!DFN[v])
{
Tarjan(v);
if (Low[u] > Low[v]) Low[u] = Low[v];
}
else if (Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if (Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}while (v != u);
}
} void deal()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
Index = top = ;
scc = ;
memset(num,,sizeof(num));
for (int i = ; i <= N ; i++)
{
if (!DFN[i]) Tarjan(i);
}
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
if (N == && M == ) break;
init();
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,);
}
deal();
printf("%s\n",scc == ? "Yes" : "No");
}
return ;
}
POJ 2767 Proving Equivalences
强联通推证明题 缩点后统计入度出度为0的点。具体答案是max(cntdegout = 0,cntdegin = 0)。很水直接看代码
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N,M;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN]; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!DFN[v])
{
Tarjan(v);
if (Low[u] > Low[v]) Low[u] = Low[v];
}
else if (Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if (Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}while (v != u);
}
} void deal()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
top = Index = scc = ;
memset(num,,sizeof(num));
memset(degin,,sizeof(degin));
memset(degout,,sizeof(degout));
for (int i = ; i <= N ; i++)
{
if (!DFN[i]) Tarjan(i);
}
if (scc == )
{
puts("");
return;
}
int ret1 = ,ret2 = ;
for (int i = ; i < tot ; i++)
{
int v = Belong[edge[i].v];
int u = Belong[edge[i].u];
if (u == v) continue;
degin[v]++;
degout[u]++;
}
for (int i = ; i <= scc ; i++)
{
if (degin[i] == ) ret1++;
if (degout[i] == ) ret2++;
}
printf("%d\n",max(ret1,ret2));
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&N,&M);
init();
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,);
}
deal();
}
return ;
}
HDU 3836 Equivalent Sets
与上题一样
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N,M;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN]; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!DFN[v])
{
Tarjan(v);
if (Low[u] > Low[v]) Low[u] = Low[v];
}
else if (Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if (Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}while (v != u);
}
} void deal()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
top = Index = scc = ;
memset(num,,sizeof(num));
memset(degin,,sizeof(degin));
memset(degout,,sizeof(degout));
for (int i = ; i <= N ; i++)
{
if (!DFN[i]) Tarjan(i);
}
if (scc == )
{
puts("");
return;
}
int ret1 = ,ret2 = ;
for (int i = ; i < tot ; i++)
{
int v = Belong[edge[i].v];
int u = Belong[edge[i].u];
if (u == v) continue;
degin[v]++;
degout[u]++;
}
for (int i = ; i <= scc ; i++)
{
if (degin[i] == ) ret1++;
if (degout[i] == ) ret2++;
}
printf("%d\n",max(ret1,ret2));
} int main()
{
int T;
while(scanf("%d%d",&N,&M) != EOF)
{
init();
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,);
}
deal();
}
return ;
}
HDU 1827 Summer Holiday
强连通缩点,统计入度为0的就是要通知的人,对于每一个强连通分量只需要通知里面代价最小的那个更新答案即可。水题
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N,M;
int ret;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];
bool flag[MAXN];
int val[MAXN]; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!DFN[v])
{
Tarjan(v);
if (Low[u] > Low[v]) Low[u] = Low[v];
}
else if (Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if (Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}while (v != u);
}
} void calcu()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
Index = top = scc = ;
int ans = ,ret = ;
memset(flag,false,sizeof(flag));
memset(degin,,sizeof(degin));
memset(degout,,sizeof(degout));
for (int i = ; i <= N ; i++)
{
if (!DFN[i]) Tarjan(i);
}
for (int i = ; i < tot ; i++)
{
int u = Belong[edge[i].u];
int v = Belong[edge[i].v];
if (u == v) continue;
degin[v]++;
degout[u]++;
}
for (int i = ; i <= scc ; i++)
{
if (degin[i] == )
{
ans++;
int tmp = INF;
for (int j = ; j <= N ; j++)
{
if (Belong[j] == i)
tmp = min(tmp,val[j]);
}
ret += tmp;
}
} printf("%d %d\n",ans,ret);
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
for (int i = ; i <= N ; i++)scanf("%d",&val[i]);
init();
for (int i = ; i <= M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,);
}
calcu();
}
return ;
}
HDU 3072 Intelligence System
给了一个含有 n(0<n<=50000) 个节点的有向图,图中的两点之间的通信时要付出代价的(经过的边权之和),但是如果这两个点之间相互可达,代价为 0
问,从给定的节点向其他所有的点通信,所花费的最小代价是多少
先对原图缩点,形成一个 DAG,给的那个定点显然是 DAG 中入度为 0 的点,并且入度为 0 的点肯定只有一个(根据题目的意思)
每个顶点(除了那个定点)必定只有一个入点,那么,对于每个顶点,完全可以选择代价最小的那条入点,贪心的找即可
做了好久忘了咋做的了。上面你的题解是复制的。解法是一样的具体看代码。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N,M;
int ret;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];
bool flag[MAXN];
int val[MAXN]; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!DFN[v])
{
Tarjan(v);
if (Low[u] > Low[v]) Low[u] = Low[v];
}
else if (Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if (Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}while (v != u);
}
} void calcu()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
memset(degin,,sizeof(degin));
memset(degout,,sizeof(degout));
Index = top = scc = ;
for (int i = ; i < N ; i++)
{
if (!DFN[i]) Tarjan(i);
}
memset(val,0x3f,sizeof(val));
for (int i = ; i < tot ; i++)
{
int u = Belong[edge[i].u];
int v = Belong[edge[i].v];
if (u == v) continue;
val[v] = min(val[v] ,edge[i].w);
// printf("%d %d %d\n",v,val[v],edge[i].w);
//printf("%d\n",edge[i].w);
}
LL ret = ;
for (int i = ; i <= scc ; i++)
ret += 1LL * val[i];
printf("%lld\n",ret - INF);
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
init();
int u,v,w;
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
}
calcu();
}
return ; }
HDU 3639 Hawk-and-Chicken
有 n(2<=n<=5000) 个人,m(0<m<=30000) 个 support 关系(A support B)。问:哪些人得到的 support 最多。
需要注意的是 support 是可以传递的,比如:A support B && B support C,那么,C 得到的 support 是 2
做法:强连通缩点,出度为0的点就是我们要的可能的最大support。为什么代码里是入度,我记得要处理出这个连通分量里的点是什么。而正向处理是比较麻烦的。
所以变成建反图,从入度为0点处理
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N,M;
int ret;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];
bool flag[MAXN];
int val[MAXN]; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!DFN[v])
{
Tarjan(v);
if (Low[u] > Low[v]) Low[u] = Low[v];
}
else if (Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if (Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}while (v != u);
}
} vector<int>G[MAXN];
int sum;
bool vis[MAXN]; void dfs(int u)
{
vis[u] = true;
sum += num[u];
for (int i = ; i < (int)G[u].size() ; i++)
{
int v = G[u][i];
if (vis[v]) continue;
dfs(v);
}
} vector<int>ans;
int res[MAXN];
void calcu(int kase)
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
memset(res,-,sizeof(res));
memset(num,,sizeof(num));
top = Index = scc = ;
for (int i = ; i < N ; i++)
{
if (!DFN[i]) Tarjan(i);
}
memset(degin,,sizeof(degin));
memset(degout,,sizeof(degout));
for (int i = ; i <= scc ; i++) G[i].clear();
for (int i = ; i < tot ; i++)
{
int u = Belong[edge[i].u];
int v = Belong[edge[i].v];
if (u == v) continue;
G[v].push_back(u);
degin[u]++;
degout[v]++;
// printf("%d %d\n",v,u);
}
int ret = ;
for (int i = ; i <= scc ; i++)
{
if (degin[i] == )
{
sum = ;
memset(vis,false,sizeof(vis));
dfs(i);
res[i] = sum;
if (sum > ret)
{
ret = sum;
}
}
}
//cout << ret << endl;
ans.clear();
for (int i = ; i < N ; i++)
{
if (res[Belong[i]] == ret)
{
ans.push_back(i);
}
}
printf("Case %d: %d\n",kase++,ret - );
for (int i = ; i < (int)ans.size() ; i++)
{
printf("%d%c",ans[i],i == ans.size() - ? '\n' : ' ');
}
} int main()
{
int kase = ,T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&N,&M);
init();
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,);
}
calcu(kase++);
}
return ;
}
HDU 3594 Cactus
仙人掌图+tarjan
我看了别人的题解弄的。代码里有解释和别人的题解链接
/*
题目大意:给你一个图,让你判断他是不是仙人掌图。 仙人掌图的条件是: 1、是强连通图。 2、每条边在仙人掌图中只属于一个强连通分量。 仙人掌图介绍 --> http://files.cnblogs.com/ambition/cactus_solution.pdf 解题思路: 1、首先得先熟练掌握塔尖tarjan算法的应用。 2、必须了解仙人掌图的三个性质: (1).仙人掌dfs图中不能有横向边,简单的理解为每个点只能出现在一个强联通分量中。 (2).low[v]<dfn[u],其中u为v的父节点 (3).a[u]+b[u]<2 , a[u]为u节点的儿子节点中有a[u]个low值小于u的dfn值。b[u]为u的逆向边条数。 三个性质有一个不满足则不是仙人掌图。
*/ #include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int fa[MAXN];
int Find(int x) {return x == fa[x] ? x : fa[x] = Find(fa[x]);}
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N,M;
int ret;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN]; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} bool flag;
void Tarjan(int u)
{
int v;
int cnt = ;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!DFN[v])
{
Tarjan(v);
if (Low[v] > DFN[u]) flag = false;;
if (Low[v] < DFN[u]) cnt++;
if (cnt >= ) flag = false;
if (Low[u] > Low[v]) Low[u] = Low[v];
}
else if (Instack[v])
{
Low[u] = min(Low[u],DFN[v]);
cnt++;
if (cnt >= ) flag = false;
}
}
if (Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}while (v != u);
}
} bool calcu()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
top = Index = scc = ;
flag = true;
for (int i = ; i < N ; i++)
{
if (!DFN[i]) Tarjan(i);
}
// for (int i = 0 ; i < N ; i++) printf("%d ",Belong[i]); putchar('\n');
// printf("%d\n",scc);
if (scc != ) return false;
return flag;
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d",&N);
init();
int u,v;
while (scanf("%d%d",&u,&v) != EOF)
{
if (u == && v == ) break;
add_edge(u,v,);
}
if (calcu()) puts("YES");
else puts("NO");
}
return ;
}
HDU 2242 考研路茫茫――空调教室
枚举桥然后处理处每个点孩子的总数直接做就行
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
int id;
bool cut;
};
Edge edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
bool Instack[MAXN];
bool cut[MAXN];
int num[MAXN];
int add_block[MAXN],N,M;
int bridge,block;
int son[MAXN],val[MAXN];
int sum;
vector<int>G[MAXN];
bool vis[MAXN];
int dep[MAXN];
int ret; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int id,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].id = id;
edge[tot].next = head[u];
edge[tot].cut = false;
head[u] = tot++;
} void Tarjan(int u,int pre)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
v = edge[i].v;
if (!DFN[v])
{
Tarjan(v,edge[i].id);
if (Low[u] > Low[v]) Low[u] = Low[v];
if (Low[v] > DFN[u])
{
bridge++;
edge[i].cut = true;
edge[i ^ ].cut = true;
}
}
else if (DFN[v] < DFN[u] && edge[i].id != pre)
Low[u] = min(Low[u],DFN[v]);
}
if (Low[u] == DFN[u])
{
block++;
do
{
v = Stack[--top];
Instack[v] = true;
Belong[v] = block;
son[block] += val[v];
}while (v != u);
}
} void dfs(int u,int fa)
{
vis[u] = true;
son[u] = num[u];
for (int i = ; i < (int)G[u].size() ; i++)
{
int v = G[u][i];
if (v == fa || vis[v]) continue;
dep[v] = dep[u] + ;
dfs(v,u);
son[u] += son[v];
}
} void calcu()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
memset(num,,sizeof(num));
Index = top = block = ;
for (int i = ; i < N ; i++)
{
if (!DFN[i]) Tarjan(i,-);
}
// for (int i = 0 ; i < N ; i++) printf("%d\n",Belong[i]);
for (int i = ; i < N ; i++) num[Belong[i]] += val[i];
// for (int i = 1 ; i <= block ; i++) printf("%d ",num[i]); putchar('\n');
if (block == )
{
puts("impossible");
return;
}
for (int i = ; i <= block ; i++) G[i].clear();
for (int i = ; i < tot ; i++)
{
if (edge[i].cut)
{
int u = Belong[edge[i].u];
int v = Belong[edge[i].v];
G[u].push_back(v);
G[v].push_back(u);
}
}
dep[] = ;
memset(vis,false,sizeof(vis));
memset(son,,sizeof(son));
dfs(,-);
// for (int i = 1 ; i <= block ; i++) printf("%d ",son[i]); putchar('\n');
int ret = INF;
//printf("%d\n",sum);
for (int i = ; i < tot ; i++)
{
if (edge[i].cut)
{
int u = Belong[edge[i].u];
int v = Belong[edge[i].v];
if (dep[u] < dep[v])
{
ret = min(ret,abs(sum - * son[v]));
}
else
{
ret = min(ret,abs(sum - * son[u]));
}
}
}
printf("%d\n",ret);
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
sum = ;
for (int i = ; i < N ; i++) scanf("%d",&val[i]);
for (int i = ; i < N ; i++) sum += val[i];
init();
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,i + ,);
add_edge(v,u,i + ,);
}
calcu();
}
return ;
}
HDU 2460 Network
a数组记得是表示以该点为桥边的较深点的桥是否已经被删除过
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
struct Edge
{
int u,v,w;
int next;
int id;
bool cut;
}edge[MAXM];
int head[MAXN],tot;
int N,M;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int block;
bool Instack[MAXN];
int bridge; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w,int id)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].id = id;
edge[tot].cut = false;
edge[tot].next = head[u];
head[u] =tot++;
} void Tarjan(int u,int pre)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
int son = ;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
v = edge[i].v;
if (!DFN[v])
{
son++;
Tarjan(v,edge[i].id);
if (Low[u] > Low[v]) Low[u] = Low[v];
if (Low[v] > DFN[u])
{
bridge++;
edge[i].cut = true;
edge[i ^ ].cut = true;
}
}
else if (DFN[v] < DFN[u] && edge[i].id != pre)
Low[u] = min(Low[u],DFN[v]);
}
if (Low[u] == DFN[u])
{
block++;
do
{
v = Stack[--top];
Instack[v] = true;
Belong[v] = block;
}while (v != u);
}
} vector<int>vec[MAXN];
int father[MAXN],dep[MAXN],a[MAXN];
void LCA_bfs(int root)
{
memset(dep,-,sizeof(dep));
dep[root] = ;
a[root] = ;
father[root] = -;
queue<int>q;
q.push(root);
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i = ; i < (int)vec[u].size() ; i++)
{
int v = vec[u][i];
if (dep[v] != -) continue;
dep[v] = dep[u] + ;
a[v] = ;
father[v] = u;
q.push(v);
}
}
} int ret;
void lca(int u,int v)
{
if (dep[u] > dep[v]) swap(u,v);
while (dep[u] < dep[v])
{
if (a[v])
{
ret--;
a[v] = ;
}
v = father[v];
}
while (u != v)
{
if (a[u])
{
ret--;
a[u] = ;
}
if (a[v])
{
ret--;
a[v] = ;
}
u = father[u];
v = father[v];
}
} void calcu(int N)
{
memset(Instack,false,sizeof(Instack));
memset(DFN,,sizeof(DFN));
Index = top = block = ;
bridge = ;
for (int i = ; i <= N ; i++)
if (!DFN[i]) Tarjan(i,-);
for (int i = ; i <= N ; i++)
vec[i].clear();
for (int u = ; u <= N ; u++)
{
for (int i = head[u] ; i != - ; i = edge[i].next)
{
if (edge[i].cut == false) continue;
int v = edge[i].v;
vec[Belong[u]].push_back(Belong[v]);
vec[Belong[v]].push_back(Belong[u]);
}
}
// printf("%d\n",bridge);
LCA_bfs();
ret = block - ;
int Q;
scanf("%d",&Q);
while (Q--)
{
int u,v;
scanf("%d%d",&u,&v);
lca(Belong[u],Belong[v]);
printf("%d\n",ret);
}
putchar('\n');
} int main()
{
// freopen("sample.txt","r",stdin);
int kase = ;
while (scanf("%d%d",&N,&M) != EOF)
{
if (N == && M == ) break;
printf("Case %d:\n",kase++);
init();
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,,i);
add_edge(v,u,,i);
}
calcu(N);
}
return ;
}
HDU 3849 By Recognizing These Guys, We Find Social Networks Useful
读完提就会做。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int N,M;
struct Edge
{
int u,v,w;
int next;
// int id;
bool cut;
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int block;
bool Instack[MAXN];
int bridge; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w,int id = )
{
edge[tot].u = u;
edge[tot].v = v;
// edge[tot].id = id;
edge[tot].cut = false;
edge[tot].next = head[u];
head[u] =tot++;
} void Tarjan(int u,int pre)
{
int v;
Low[u] = DFN[u] = ++Index;
Instack[u] = true;
Stack[top++]= u;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (v == pre) continue;
if (!DFN[v])
{
Tarjan(v,u);
if (Low[u] > Low[v]) Low[u] = Low[v];
if (Low[v] > DFN[u])
{
bridge++;
edge[i].cut = true;
edge[i ^ ].cut = true;
}
}
else if (Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if (Low[u] == DFN[u])
{
block++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = block;
}while (u != v);
}
} map<string,int>mp;
map<int,string>res; void calcu()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
Index = top = block = ;
bridge = ;
Tarjan(,);
for (int i = ; i <= N ; i++)
{
if (!DFN[i])
{
puts("");
return;
}
}
printf("%d\n",bridge);
for (int i = ; i < tot ; i += )
{
if (edge[i].cut == false) continue;
//printf("%s %s\n",res[edge[i].u],res[edge[i].v]);
cout << res[edge[i].u] << " " << res[edge[i].v] << endl;
}
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&N,&M);
init();
mp.clear();
res.clear();
int cas = ;
for (int i = ; i <= M ; i++)
{
int u,v;
char src[],tag[];
scanf("%s%s",src,tag);
if (!mp[src])
{
res[cas] = src;
mp[src] = cas++;
}
if (!mp[tag])
{
res[cas] = tag;
mp[tag] = cas++;
}
u = mp[src];
v = mp[tag];
add_edge(u,v,);
add_edge(v,u,);
}
calcu();
}
return ;
}
HDU 3896 Greatest TC
搜了题解做的。代码里有我搜的题解的解析。太弱了orz
/*
给出一个无向图,询问两个点在删去一条边或者一个点以后能否到达。 生成一颗dfs树,然后记录dfn[]、low[]、final[]、deep[]。Final表示离开这个节点的时间。
对于边的询问,询问的节点是a,b,设这个边为g1-g2,其中deep[g1]>deep[g2]。
1. a在g1的子树内,b也在g1的子树内,那么a、b可以到达。
2. a不在g1的子树内,b也不在g1的子树内,那么a、b可以到达。
3. 不妨假设a在g1的子树内,b不在g1的子树内,则判断low[g1]是否≤dfn[g2]。如果是的话,那么a、b可以到达。
4. 其他情况下不能到达。
对于点的询问,询问的节点是a,b,设这个点为g1:
1. 如果a,b都不在g1的子树内。则可行
2. 如果a,b有一个在g1的子树内(设为a),求出在a-g1路径上的倒数第二个点k,如果low[k] < dfn[g1]则可行
3. 如果a,b都在g1的子树内。求出在a-g1路径上的倒数第二个点k1,在b-g1路径上的倒数第二个点k2,判断是否两者的low都<dfn[g1]则可行
4. 其他情况下不能到达。 如何判断一个点a是否在g的子树内:
Dfn[a] >= dfn[g] 且 final[a] <= final[g]
开始怎么都a不了。后然问了学长才发现对于点询问如果a,b,都在g1子树中,如果k1=k2那么直接输出yes好了。。wa了N多次。。
*/ #include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int N,M;
struct Edge
{
int u,v,w;
int next;
// int id;
bool cut;
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int dep[MAXN];
int leave[MAXN];
int fa[MAXN];
int block;
bool vis[MAXM];
bool Instack[MAXN];
int bridge; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w,int id = )
{
edge[tot].u = u;
edge[tot].v = v;
// edge[tot].id = id;
edge[tot].cut = false;
edge[tot].next = head[u];
head[u] =tot++;
} void Tarjan(int u,int pre,int depth)
{
Low[u] = DFN[u] = ++Index;
dep[u] = depth ;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
if (vis[i]) continue;
vis[i] = vis[i ^ ] = true;
int v = edge[i].v;
if (!DFN[v])
{
Tarjan(v,u,depth + );
fa[v] = u;
Low[u] = min(Low[u],Low[v]);
}
else
Low[u] = min(Low[u],DFN[v]);
}
leave[u] = Index;
} void calcu()
{
memset(vis,false,sizeof(vis));
memset(DFN,,sizeof(DFN));
memset(fa,-,sizeof(fa));
Index = top = block = ;
bridge = ;
for (int i = ; i <= N ; i++)
{
if (!DFN[i]) Tarjan(i,i,);
}
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
// printf("N = %d M = %d\n",N,M);
init();
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,);
add_edge(v,u,);
}
calcu();
int Q;
scanf("%d",&Q);
// printf("Q = %d\n",Q);
while (Q--)
{
int op;
scanf("%d",&op);
if (op == )
{
int u,v,g1,g2;
scanf("%d%d%d%d",&u,&v,&g1,&g2);
bool flag1 = false,flag2 = false;
if (dep[g1] < dep[g2]) swap(g1,g2);
if (DFN[u] >= DFN[g1] && leave[u] <= leave[g1]) flag1 = true;
if (DFN[v] >= DFN[g1] && leave[v] <= leave[g1]) flag2 = true;
if ((flag1 && flag2) || (!flag1 && !flag2))
{
puts("yes");
}
else
{
if (Low[g1] <= DFN[g2])
{
puts("yes");
}
else
{
puts("no");
}
}
}
else
{
int u,v,g1;
scanf("%d%d%d",&u,&v,&g1);
if (u == g1 || v == g1)
{
puts("no");
continue;
}
bool flag1 = false,flag2 = false;
if (DFN[u] >= DFN[g1] && leave[u] <= leave[g1]) flag1 = true;
if (DFN[v] >= DFN[g1] && leave[v] <= leave[g1]) flag2 = true;
if (!flag1 && !flag2)
{
puts("yes");
continue;
}
if (flag1 && !flag2)
{
int x = u;
while (fa[x] != g1)
x = fa[x];
if (Low[x] < DFN[g1])
puts("yes");
else puts("no");
continue;
}
if (flag2 && !flag1)
{
int y = v;
while (fa[y] != g1)
y = fa[y];
if (Low[y] < DFN[g1])
puts("yes");
else puts("no");
continue;
}
if (flag1 && flag2)
{
int x = u;
while (fa[x] != g1) x = fa[x];
int y = v;
while (fa[y] != g1) y = fa[y];
if (x == y)
{
puts("yes");
continue;
}
if (Low[x] < DFN[g1] && Low[y] < DFN[g1])
puts("yes");
else
puts("no");
continue;
}
puts("no");
}
}
}
return ;
}
HDU 4005 The war
比较难的题目。所点后从最小桥边两个点为起点DFS,找到次小值为答案
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w,id;
bool cut;
friend bool operator < (const Edge &a,const Edge &b)
{
return a.w < b.w;
}
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
bool Instack[MAXN];
bool cut[MAXN];
int add_block[MAXN];
int bridge,block;
int N,M; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int w,int id)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].id = id;
edge[tot].next = head[u];
edge[tot].cut = false;
head[u] = tot++;
} void Tarjan(int u,int pre)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
int son = ;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
v = edge[i].v;
if (edge[i].id == pre) continue;
if (!DFN[v])
{
son++;
Tarjan(v,edge[i].id);
if (Low[u] > Low[v]) Low[u] = Low[v];
if (Low[v] > DFN[u])
{
bridge++;
edge[i].cut = true;
edge[i ^ ].cut = true;
}
}
else if (DFN[v] < DFN[u] && edge[i].id != pre)
Low[u] = min(Low[u],DFN[v]);
}
if (Low[u] == DFN[u])
{
block++;
do
{
v = Stack[--top];
Instack[v] = true;
Belong[v] = block;
}while (v != u);
}
} vector<Edge>G[MAXN];
int ret;
int dfs(int u,int fa)
{
int fir = INF,sec = INF,tmp,val;
for (int i = ; i < (int)G[u].size() ; i++)
{
int v = G[u][i].v;
if (v == fa) continue;
val = G[u][i].w;
sec = min(sec,val);
tmp = dfs(v,u);
sec = min(sec,tmp);
if (fir > sec) swap(fir,sec);
}
ret = min(ret,sec);
return fir;
} void calcu()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
Index = bridge = block = ;
top = ;
for (int i = ; i <= N ; i++)
{
if (!DFN[i]) Tarjan(i,-);
}
// printf("%d\n",block);
if (block == )
{
puts("-1");
return;
}
for (int i = ; i <= N ; i++) G[i].clear();
int posu = -,val = INF,posv = -;
for (int i = ; i < tot ; i++)
{
if (edge[i].cut)
{
int u = Belong[edge[i].u];
int v = Belong[edge[i].v];
Edge tmp;
tmp.u = u;
tmp.v = v;
tmp.w = edge[i].w;
tmp.cut = true;
G[u].push_back(tmp);
if (edge[i].w < val)
{
posu = u;
val = edge[i].w;
posv = v;
}
}
}
for (int i = ; i <= block ; i++) sort(G[i].begin() ,G[i].end());
/*for (int i = 1 ; i <= block ; i++)
{
printf("%d :\n",i);
for (int j = 0 ; j <(int)G[i].size() ; j++)
{
printf("%d ",G[i][j].v);
}
putchar('\n');
}*/
//printf("%d %d\n",posu,posv);
if (posu == - || posv == -)
{
puts("-1");
return;
}
ret = INF;
dfs(posu,posv);
dfs(posv,posu);
printf("%d\n",ret >= INF ? - : ret);
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
init();
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w,i + );
add_edge(v,u,w,i + );
}
calcu();
}
return ;
}
HDU 3394 Railway
做了这么多题这是第一道点连通分量的题目。可以的。。一直WA以为是边联通就对。。(⊙﹏⊙)b
注意割点可以属于多个双连通分量
//注意这里是点双联通而且又一个重要的。不可以直接TARJAN后处理Belong然后在处理多余边。一定不可以
//一定要在TARJAN处理处一个联通快就直接更新答案、原因就是这里的是点双联通
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int N,M;
struct Edge
{
int u,v,w;
int next;
// int id;
bool cut;
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int cnt[MAXN];
int block;
bool Instack[MAXN];
int num[MAXN];
bool vis[MAXN];
vector<int>res;
int bridge,ret; void init()
{
tot = ;
memset(head,-,sizeof(head));
} stack<Edge>S; void add_edge(int u,int v,int w,int id = )
{
edge[tot].u = u;
edge[tot].v = v;
// edge[tot].id = id;
edge[tot].cut = false;
edge[tot].next = head[u];
head[u] = tot++;
} void update()
{
memset(vis,false,sizeof(vis));
int sum = ;
for (int i = ; i < (int)res.size() ; i++)
{
int u = res[i];
vis[u] = true;
}
for (int i = ; i <(int)res.size() ; i++)
{
int u =res[i];
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (vis[v]) sum++;
}
}
sum /= ;
if (sum > res.size()) ret += sum;
} void Tarjan(int u,int fa)
{
Low[u] = DFN[u] = ++Index;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (v == fa) continue;
Edge tmp;
tmp.u = u;
tmp.v = v;
if (!DFN[v])
{
S.push(tmp);
Tarjan(v,u);
Low[u] = min(Low[u],Low[v]);
if(Low[v] >= DFN[u])//u是割点
{
if(Low[v] > DFN[u])
{
bridge++;
edge[i].cut = true;
edge[i ^ ].cut = true;
}
block++;
res.clear();
while(true)
{
Edge x = S.top(); S.pop();
if(Belong[x.u] != block)
{
res.push_back(x.u);
Belong[x.u] = block;
}
if(Belong[x.v] != block)
{
res.push_back(x.v);
Belong[x.v] = block;
}
if(x.u==u && x.v==v) break;
}
update();
}
}
else if(DFN[v] < DFN[u] && v != fa)
{
S.push(tmp);
Low[u] = min(Low[u],DFN[v]);
}
}
} void calcu()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
memset(num,,sizeof(num));
memset(Belong,,sizeof(Belong));
Index = top = block = bridge = ;
ret = ;
for (int i = ; i < N ; i++)
{
if (!DFN[i]) Tarjan(i,-);
}
printf("%d %d\n",bridge,ret);
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
if (N == && M == ) break;
init();
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,);
add_edge(v,u,);
}
calcu();
}
return ;
}
HDU 2874 Connections between cities
倍增无难度
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * ;
const int INF = 0x3f3f3f3f;
int FA[MAXN];
int Find(int x) {return x == FA[x] ? x : FA[x] = Find(FA[x]);}
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int head[MAXN],tot;
int N,M; void init()
{
memset(head,-,sizeof(head));
tot = ;
for (int i = ; i <= N ; i++) FA[i] = i;
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} int dep[MAXN],fa[MAXN],cost[MAXN];
int sumcost[MAXN][],anc[MAXN][];
bool vis[MAXN]; void bfs(int root)
{
queue<int>q;
q.push(root);
vis[root] = true;
fa[root] = -;
dep[root] = ;
cost[root] = ;
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (vis[v]) continue;
dep[v] = dep[u] + ;
cost[v] = edge[i].w;
fa[v] = u;
vis[v] = true;
q.push(v);
}
}
} void preprocess()
{
memset(sumcost,,sizeof(sumcost));
for (int i = ; i <= N ; i++)
{
anc[i][] = fa[i];
sumcost[i][] = cost[i];
for (int j = ; ( << j) <= N ; j++) anc[i][j] = -;
}
for (int j = ; ( << j) <= N ; j++)
{
for (int i = ; i <= N ; i++)
{
if (anc[i][j - ] != -)
{
int a = anc[i][j - ];
anc[i][j] = anc[a][j - ];
sumcost[i][j] = sumcost[i][j - ] + sumcost[a][j - ];
}
}
}
} int query(int p,int q)
{
int tmp,log;
if (dep[p] < dep[q]) swap(p,q);
for (log = ; ( << log) <= dep[p] ; log++); log--;
int ans = ;
for (int i = log ; i >= ; i--)
{
if (dep[p] - ( << i) >= dep[q])
{
ans += sumcost[p][i];
p = anc[p][i];
}
}
if (p == q) return ans;
for (int i = log ; i >= ; i--)
{
if (anc[p][i] != - && anc[p][i] != anc[q][i])
{
ans += sumcost[p][i]; p = anc[p][i];
ans += sumcost[q][i]; q = anc[q][i];
}
}
ans += cost[p];
ans += cost[q];
return ans;
} int main()
{
int M,C;
while (scanf("%d%d%d",&N,&M,&C) != EOF)
{
init();
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
int fu = Find(u);
int fv = Find(v);
if (fu != fv) FA[fu] = fv;
}
memset(vis,false,sizeof(vis));
for (int i = ; i <= N ; i++) if (!vis[i])
bfs(i);
preprocess();
while (C--)
{
int u,v;
scanf("%d%d",&u,&v);
int fu = Find(u);
int fv = Find(v);
// printf("%d %d %d %d\n",u,v,fu,fv);
if (fu == fv)
{
printf("%d\n",query(u,v));
}
else puts("Not connected");
}
}
return ;
}
HDU 3078 Network
直接暴力居然不会T。我也不知道为啥。
所以做法就是直接爆。修改就直接该。Nothing more
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int head[MAXN],tot;
int N,K; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} int dep[MAXN],fa[MAXN],val[MAXN];
int anc[MAXN][];
bool vis[MAXN]; int src[MAXN],cnt;
int cmp(const int &a,const int &b)
{
return a > b;
} void bfs(int root)
{
memset(vis,false,sizeof(vis));
queue<int>q;
q.push(root);
vis[root] = true;
fa[root] = -;
dep[root] = ;
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (vis[v]) continue;
dep[v] = dep[u] + ;
fa[v] = u;
vis[v] = true;
q.push(v);
}
}
} void preprocess()
{
for (int i = ; i <= N ; i++)
{
anc[i][] = fa[i];
for (int j = ; ( << j) <= N ; j++) anc[i][j] = -;
}
for (int j = ; ( << j) <= N ; j++)
{
for (int i = ; i <= N ; i++)
{
if (anc[i][j - ] != -)
{
int a = anc[i][j - ];
anc[i][j] = anc[a][j - ];
}
}
}
} int query(int p,int q)
{
int tmp,log;
if (dep[p] < dep[q]) swap(p,q);
for (log = ; ( << log) <= dep[p] ; log++); log--;
for (int i = log ; i >= ; i--)
{
if (dep[p] - ( << i) >= dep[q])
{
p = anc[p][i];
}
}
if (p == q) return p;
for (int i = log ; i >= ; i--)
{
if (anc[p][i] != - && anc[p][i] != anc[q][i])
{
p = anc[p][i];
q = anc[q][i];
}
};
return fa[p];
} void update(int u,int ed)
{
while (u != ed)
{
src[++cnt] = val[u];
u = fa[u];
}
} void slove(int u,int v)
{
int lca = query(u,v);
// printf("%d %d %d\n",u,v,lca);
cnt = ;
update(u,lca);
update(v,lca);
src[++cnt] = val[lca];
if (cnt < K)
{
puts("invalid request!");
return;
}
sort(src + ,src + + cnt,cmp);
printf("%d\n",src[K]);
} int main()
{
int Q;
while (scanf("%d%d",&N,&Q) != EOF)
{
init();
for (int i = ; i <= N ; i++) scanf("%d",&val[i]);
for (int i = ; i < N ; i++)
{
int u,v,w;
scanf("%d%d",&u,&v);
add_edge(u,v,);
add_edge(v,u,);
}
bfs();
// printf("%d %d %d %d %d\n",fa[1],fa[2],fa[3],fa[4],fa[5]);
preprocess();
while (Q--)
{
int op;
scanf("%d",&op);
if (op == )
{
int u,cost;
scanf("%d%d",&u,&cost);
val[u] = cost;
}
else
{
K = op;
int u,v;
scanf("%d%d",&u,&v);
slove(u,v);
}
}
}
return ;
}
HDU 3830 Checkers
这题真的神。我醉了。完全抄的比人的代码。感觉如果比赛除了这题必然不会。。膜拜一下
题解看这里讲的非常详细
http://www.cnblogs.com/scau20110726/archive/2013/06/14/3135024.html
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
struct state
{
LL x,y,z;
LL dep;
}S,T; inline bool cmp_state(const state &a,const state &b)
{
if (a.x == b.x && a.y == b.y && a.z == b.z) return true;
return false;
} inline void makeorder(state &a)
{
LL tmp[];
tmp[] = a.x;
tmp[] = a.y;
tmp[] = a.z;
sort(tmp,tmp + );
a.x = tmp[];
a.y = tmp[];
a.z = tmp[];
} state Root(state &a)
{
state tmp = a;
tmp.dep = ;
LL dep = ;
while(abs(tmp.x - tmp.y) != abs(tmp.y - tmp.z))
{
LL len = abs(tmp.x - tmp.y);
LL __len = abs(tmp.y- tmp.z);
if(__len > len)
{
LL c = (__len - )/ len;
dep += c;
tmp.y += c * len;
tmp.x += c * len;
}
else
{
LL c = (len - ) / __len;
dep += c;
tmp.y -= c * __len;
tmp.z -= c * __len;
}
}
a.dep = dep;
return tmp;
} void update(state &a ,LL delta)
{
LL cnt = ;
while(cnt < delta)
{
LL len = abs(a.x - a.y);
LL __len = abs(a.y - a.z);
LL k = abs(cnt - delta); //还差多少步
if(len < __len)
{
LL c = (__len - ) / len; //将要移动多少步
LL Min = min(k , c);
a.x += Min * len;
a.y += Min * len;
cnt += Min;
if(Min == k) break;
}
else
{
LL c = (len - ) / __len;
LL Min = min(k , c);
a.y -= Min * __len;
a.z -= Min * __len;
cnt += Min;
if(Min == k) break;
}
}
a.dep -= delta;
} LL calcu()
{
state tmpS,tmpT;
LL low = ,high = S.dep;
while (low <= high)
{
LL mid = (low + high) / ;
LL delta = S.dep - mid;
tmpS = S;
tmpT = T;
update(tmpS,delta);
update(tmpT,delta);
if (!cmp_state(tmpS,tmpT)) high = mid - ;
else low = mid + ;
}
return * (S.dep - high);
} int main()
{
while (scanf("%I64d%I64d%I64d",&S.x,&S.y,&S.z) != EOF)
{
scanf("%I64d%I64d%I64d",&T.x,&T.y,&T.z);
S.dep = T.dep = ;
makeorder(S);
makeorder(T);
state rs = Root(S);
state rt = Root(T);
if (!cmp_state(rs,rt))
{
puts("NO");
continue;
}
LL tmpr = abs(S.dep - T.dep);
// printf("%I64d %I64d %I64d\n",T.x,T.y,T.z);
if (S.dep > T.dep) update(S,S.dep - T.dep);
else update(T,T.dep - S.dep);
LL ret = calcu();
puts("YES");
printf("%I64d\n",ret + tmpr);
}
return ;
}
HDU 4338 Simple Path
很考验玛丽的一道题、具体怎么做的不太好说。看这里吧。他说的比较好。
就是通过割点。点双连通分量建树,然后树上的关系更新出答案,去重。割点要单独为1个点。
如果查询的点就是割点要选择单独割点为新点的那个店作为新图 。其余情况选择点双连通分量的那个店
这个非常详细 http://blog.csdn.net/julyana_lin/article/details/8128352
代码如下。有些中间调试没删掉。感觉此题比较考验玛丽。仔细看一下发现其实还是很容易些的,多一份写法可能更相似更愿意去看。
#pragma comment(linker, "/STACK:102400000,102400000")
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int N,M;
struct Edge
{
int u,v,w;
int next;
// int id;
bool cut;
}edge[MAXM];
int head[MAXN],tot; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} int Low[MAXN],DFN[MAXN];
bool cut[MAXN];
int Stack[MAXN];
int deep,top,bnum,root;
int Index,cas;
vector<int>block[MAXN]; void Tarjan(int u,int pre)
{
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
bool flag = false;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (v == pre && !flag)
{
flag = true;
continue;
}
if (!DFN[v])
{
Tarjan(v,u);
Low[u] = min(Low[u],Low[v]);
if (Low[v] >= DFN[u])
{
if (pre == -) root++;
else cut[u] = true;
int tmp;
do
{
tmp = Stack[--top];
block[bnum].push_back(tmp);
}while (tmp != v);
block[bnum].push_back(u);
bnum++;
}
}
else Low[u] = min(Low[u],DFN[v]);
}
} vector<int>G[MAXN];
int lab[MAXN];
int nb[MAXN]; void calcu()
{
memset(cut,false,sizeof(cut));
memset(DFN,,sizeof(DFN));
for (int i = ; i <= N ; i++) G[i].clear();
for (int i = ; i <= N ; i++) block[i].clear();
top = bnum = Index = ;
for (int i = ; i < N ; i++)
{
if (!DFN[i])
{
root = ;
Tarjan(i,-);
if (root > ) cut[i] = true;
}
}
/*
for (int i = 0 ; i < bnum ; i++)
{
for (int j = 0 ; j < (int)block[i].size() ; j++)
printf("%d ",block[i][j]);
putchar('\n');
}*/ memset(lab,-,sizeof(lab));
cas = ;
for (int i = ; i < N ; i++)
{
if (cut[i])
{
lab[i] = cas;
nb[cas] = ;
cas++;
}
}
for (int i = ; i < bnum ; i++)
{
for (int j = ; j < (int)block[i].size() ; j++)
{
int v = block[i][j];
if (cut[v])
{
// printf("%d is cut\n",v);
G[lab[v]].push_back(cas);
G[cas].push_back(lab[v]);
}
else
lab[v] = cas;
}
nb[cas] = block[i].size();
cas++;
}
/* putchar('\n');
for (int i = 0 ; i < N ; i++) printf("%d ",lab[i]);
putchar('\n');
for (int i = 0 ; i < cas ; i++)
{
for (int j = 0 ; j < (int)G[i].size() ; j++)
printf("%d ",G[i][j]);
putchar('\n');
}
*/
} int id[MAXN];
int dep[MAXN],fa[MAXN],cost[MAXN];
int anc[MAXN][];
bool vis[MAXN]; void bfs(int root)
{
cost[root] = nb[root];
fa[root] = -;
dep[root] = ;
vis[root] = true;
queue<int>q;
q.push(root);
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i = ; i < (int)G[u].size() ; i++)
{
int v = G[u][i];
if (vis[v]) continue;
vis[v] = true;
dep[v] = dep[u] + ;
fa[v] = u;
cost[v] = cost[u] + nb[v];
q.push(v);
}
}
} void preprecess()
{
for (int i = ; i < cas ; i++)
{
anc[i][] = fa[i];
for (int j = ; ( << j) < cas ; j++) anc[i][j] = -;
}
for (int j = ; ( << j) < cas ; j++)
{
for (int i = ; i < cas ; i++)
{
if (anc[i][j - ] != -)
{
int a = anc[i][j - ];
anc[i][j] = anc[a][j - ];
}
}
}
} int query(int p,int q)
{
int tmp,log;
if (dep[p] < dep[q]) swap(p,q);
for (log = ; ( << log) <= dep[p] ; log++); log--;
for (int i = log ; i >= ; i--)
{
if (dep[p] - ( << i) >= dep[q])
p = anc[p][i];
}
if (p == q)return p;
for (int i = log ; i >= ; i--)
{
if (anc[p][i] != - && anc[p][i] != anc[q][i])
{
p = anc[p][i];
q = anc[q][i];
}
}
return fa[p];
} void col(int u,int type)
{
id[u] = type;
for (int i = ; i < (int)G[u].size() ; i++)
{
int v = G[u][i];
if (id[v] != -) continue;
col(v,type);
}
} int main()
{
int kase = ;
while (scanf("%d%d",&N,&M) != EOF)
{
init();
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,);
add_edge(v,u,);
}
calcu();
memset(dep,,sizeof(dep));
memset(vis,false,sizeof(vis));
memset(cost,,sizeof(cost));
for (int i = ; i < cas ; i++)
if (dep[i] == ) bfs(i);
// for (int i = 0 ; i < 4 ; i++)
// printf("%d %d %d %d\n",i,fa[i],dep[i],cost[i]);
preprecess();
int Q;
memset(id,-,sizeof(id));
int step = ;
for (int i = ; i < cas ; i++)
{
if (id[i] == -)
{
col(i,step);
step++;
}
}
printf("Case #%d:\n",kase++);
scanf("%d",&Q);
while (Q--)
{
int u,v;
scanf("%d%d",&u,&v);
if (u == v)
{
printf("%d\n",N - );
continue;
}
if (lab[u] == - || lab[v] == -)
{
printf("%d\n",N);
continue;
}
if (id[lab[u]] != id[lab[v]])
{
printf("%d\n",N);
continue;
}
int realu = lab[u];
int realv = lab[v];
int lca = query(realu,realv);
// printf("%d %d %d %d %d\n",u,v,realu,realv,lca);
int sum = cost[realu] + cost[realv] - * cost[lca] + nb[lca];
int len = dep[realu] + dep[realv] - * dep[lca];
printf("%d\n",N - (sum - len));
}
putchar('\n');
}
return ;
}
FZU 1719 Spy network
在缩点入度为0的点里选择权最小的求和就是答案。比较容易
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];
int val[MAXN],M;
int MIN[MAXN]; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!DFN[v])
{
Tarjan(v);
if (Low[u] > Low[v]) Low[u] = Low[v];
}
else if (Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if (Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}while (v != u);
}
} void calcu()
{
memset(DFN,,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
top = Index = scc = ;
memset(num,,sizeof(num));
for (int i = ; i <= N ; i++)
{
if (!DFN[i]) Tarjan(i);
}
memset(degin,,sizeof(degin));
memset(degout,,sizeof(degout));
memset(MIN,0x3f,sizeof(MIN));
for (int i = ; i <= N ; i++)
{
MIN[Belong[i]] = min(MIN[Belong[i]],val[i]);
}
for (int i = ; i < tot ; i++)
{
int u = Belong[edge[i].u];
int v = Belong[edge[i].v];
if(u == v) continue;
degout[u]++;
degin[v]++;
}
bool flag = false;
for (int i = ; i <= scc ; i++)
{
if (degin[i] == && MIN[i] >= INF)
{
flag = true;
break;
}
}
if (flag)
{
puts("NO");
int pos = - ;
for (int i = ; i <= N ; i++)
if (degin[Belong[i]] == && MIN[Belong[i]] >= INF)
{
printf("%d\n",i);
return;
}
}
else
{
puts("YES");
int ret = ;
for (int i = ; i <= scc ; i++) if (degin[i] == ) ret += MIN[i];
printf("%d\n",ret);
}
} int main()
{
while (scanf("%d",&N) != EOF)
{
init();
int P;
scanf("%d",&P);
memset(val,0x3f,sizeof(val));
for (int i = ; i <= P ; i++)
{
int x,value;
scanf("%d%d",&x,&value);
val[x] = min(val[x],value);
}
int M;
scanf("%d",&M);
for (int i = ; i < M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v,);
}
calcu();
}
return ;
}
Tarjan & LCA 套题题目题解的更多相关文章
- Moscow Pre-Finals Workshop 2016. Japanese School OI Team Selection. 套题详细解题报告
写在前面 谨以此篇题解致敬出题人! 真的期盼国内也能多出现一些这样质量的比赛啊.9道题中,没有一道凑数的题目,更没有码农题,任何一题拿出来都是为数不多的好题.可以说是这一年打过的题目质量最棒的五场比赛 ...
- 【qboi冲刺NOIP2017复赛试题4】 全套题目+题解+程序
作为一个好人(验题人),我给大家奉上下这套题的题解,并且预祝大家这套题能够AK: T1题面:Alice现在有n根木棍,他们长度为1,2,3....n,Bob想把某一些木棍去掉,使得Alice剩下的木棍 ...
- hdu 2586 How far away?(LCA模板题+离线tarjan算法)
How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- 第46套题【STL】【贪心】【递推】【BFS 图】
已经有四套题没有写博客了.今天改的比较快,就有时间写.今天这套题是用的图片的形式,传上来不好看,就自己描述吧. 第一题:单词分类 题目大意:有n个单词(n<=10000),如果两个单词中每个字母 ...
- 洛谷 P2194 HXY烧情侣【Tarjan缩点】 分析+题解代码
洛谷 P2194 HXY烧情侣[Tarjan缩点] 分析+题解代码 题目描述: 众所周知,HXY已经加入了FFF团.现在她要开始喜(sang)闻(xin)乐(bing)见(kuang)地烧情侣了.这里 ...
- Tarjan+LCA【洛谷P2783】 有机化学之神偶尔会做作弊
[洛谷P2783] 有机化学之神偶尔会做作弊 题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹. 然而你的化竞基友却向你求助了. ...
- 洛谷 P2783 有机化学之神偶尔会做作弊(Tarjan,LCA)
题目背景 LS中学化学竞赛组教练是一个酷爱炉石的人. 有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹. 然而你的化竞基友却向你求助了. “第1354题怎么做”<--手语 他问道 ...
- HDU2586 How far away ?(LCA模板题)
题目链接:传送门 题意: 给定一棵树,求两个点之间的距离. 分析: LCA 的模板题目 ans = dis[u]+dis[v] - 2*dis[lca(u,v)]; 在线算法:详细解说 传送门 代码例 ...
- 【套题】qbxt国庆刷题班D1
Day1 事实上D1的题目还是比较简单的= =然而D1T2爆炸了就十分尴尬--错失一波键盘 看题 T1 传送门 Description 现在你手里有一个计算器,上面显示了一个数\(S\),这个计算器十 ...
随机推荐
- fiddler抓包-简单易操作(二)
Fiddler抓包简介 原理:fiddler是通过改写HTTP代理,客户端和服务器进行交互时,数据会从他那里通过,来监控和截取数据.我是这样理解的,如果不对,欢迎指正.如下图: 如果想要抓到数据包,首 ...
- CCF-NOIP-2018 提高组(复赛) 模拟试题(九)(2018 CSYZ长沙一中)
T1 Circle [问题描述] 小 w 的男朋友送给小 w 一个 n 个点 m 条边的图,并且刁难小 w 要她找出点数最少的正环. 小 w 不会做,于是向你求助. [输入格式] 第一行两个整数\(n ...
- (原创)不过如此的 DFS 深度优先遍历
DFS 深度优先遍历 DFS算法用于遍历图结构,旨在遍历每一个结点,顾名思义,这种方法把遍历的重点放在深度上,什么意思呢?就是在访问过的结点做标记的前提下,一条路走到天黑,我们都知道当每一个结点都有很 ...
- Leetcode 3. Longest Substring Without Repeating Characters (Medium)
Description Given a string, find the length of the longest substring without repeating characters. E ...
- 九度OJ--1167(C++)
#include <iostream>#include <algorithm>#include <map> using namespace std; int mai ...
- delphi保存文件的命名规则
没有固定的标准.自己可以定义 .你可以参考PASCAL命名法则.查一下PASCAL命名. 我习惯用UMain,FMain,UDM,DM,UAboutBox,AboutBox.....程序相关内容都放在 ...
- typescript 简版跳一跳
typescript 简版跳一跳 学习typescript,第一步应该是学习官方文档,理解最基础的语法.第二步开始用typescript实现一些js+css 或者canvas类型的游行.现在开始我们用 ...
- 框架开发中的junit单元测试
首先写一个测试用的公共类,如果要搭建测试环境,只要继承这个公共类就能很容易的实现单元测试,代码如下 import org.junit.runner.RunWith; import org.spring ...
- kudu介绍及安装配置
kudu介绍及安装配置 介绍 Kudu 是一个针对 Apache Hadoop 平台而开发的列式存储管理器.Kudu 共享 Hadoop 生态系统应用的常见技术特性: 它在 commodity har ...
- BZOJ 2707: [SDOI2012]走迷宫 拓扑+高斯消元+期望概率dp+Tarjan
先Tarjan缩点 强连通分量里用高斯消元外面直接转移 注意删掉终点出边和拓扑 #include<cstdio> #include<cstring> #include<a ...