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\),这个计算器十 ...
随机推荐
- Oracle修改表字段类型(number-->varchar2(len)),亲测可用
思路: --新建临时表以存储正确的顺序create table A_2 as select (column1,colum2,……A表中的顺序) from A_1 ; --删除表A_1drop tabl ...
- cocos2d-x 键盘和鼠标事件
出了菜单可以响应用户事件外,cocos2d中的层(Layer)也可以响应事件.层能够自动响应窗口事件,这些事件主要是键盘和鼠标事件,cocos2d中事件处理是通过Pyglet的事件处理完成的. 1.键 ...
- tensorflow nmt基本配置(tf-1.4)
随着tensorflow的不断更新,直接按照nmt的教程搭建nmt环境会报错的...因此,需要一些不太好的办法来避免更多的问题出现.tensorflow看来在ubuntu和debian中运行是没有问题 ...
- struts2中的action为什么要继承ActionSupport类,不继承也可以,有什么好处?
简单来说,有很多相关的方法都加载进来,你直接调用就行了,而且在安全上和稳定性上做了很好的处理 实际上继承ActionSupport之后 就等同于实现了很多接口 Action,Validateable, ...
- Java开发JDBC连接数据库
Java开发JDBC连接数据库 创建一个以JDBC连接数据库的程序,包含6个步骤: JDBC五部曲1.加载驱动2.获得链接3.获取statement对象 4.执行SQL语句5.产生resultset对 ...
- 解决ecplise安装mybatipse插件时报找不到jar包的错
在安装mybatipse插件的时候一直报这个错,脑袋疼,在网上搜了半天也没有结果,最后摸索了半天解决了,这里先贴一张图 1.先找到eclipse的安装目录,然后把相应的jar包拷到plugins里去, ...
- LTE中基于S1的切换
1:源eNodeB决定进行基于S1的切换.S1切换的原因可能是源eNodeB和目标eNodeB之间不存在X2连接,或者源eNodeB根据其他情况作出的判断. 2:源eNodeB向源MME发送Hando ...
- springMVC js等文件找不到解决方法
<mvc:resources mapping="/javascript/**" location="/static_resources/javascript/&qu ...
- Java中WeakHashMap实现原理深究
一.前言 我发现Java很多开源框架都使用了WeakHashMap,刚开始没怎么去注意,只知道它里面存储的值会随时间的推移慢慢减少(在 WeakHashMap 中,当某个“弱键”不再正常使用时,会被从 ...
- 如何控制DBGrid里面显示的浮点数小数点后的位数?
现在dbgrid里面显示的位数太多,有10几位,根本没办法看.请问怎么设置能控制小数点后的位数呢?在c语言里面是 %7.2f就可以了,可惜不知道dephi里面怎么做啊谢谢各位指点 方法1: 把那些 ...