题目地址:http://ac.jobdu.com/problem.php?pid=1418
题目描述:
Luke 得到一张藏宝图,藏宝图上有n个城市(编号1-n),并且这些城市有一些道路相连着。每个城市里都有一份宝藏,并且宝藏图里已经把每个城市的宝藏位置描述得很清楚了,所以只要Luke能到达这个城市,他就一定能找到这个城市里的那份宝藏。
输入:
输入有多组,每组输入第一行为三个整数n,m,s(1<=n<=100000,0<=m<=150000)。分别表示城市的数量数和连接这些城市的路径数量,s为Luke的起点城市。接下来是m对整数v,u(1<=v,u<=n),表示从v到u有一条路径(路径为单向的)。
输出:
对于每组输入,先输出一行”Case T:” T从1开始。输出Luke最多能找到的宝藏数量。
样例输入:
4 3 1
1 2
2 3
2 4
5 4 1
1 2
2 3
2 4
3 2
样例输出:
Case 1:
3
Case 2:
4
强连通分量tarjan基本应用。
求出各个连通分量以后,还需要合并一下。
如果存在路径的话,把相应的连通分量合并。
我觉得这里有点像 并查集的思路,但是比并查集多了方向。
C++ AC了,Java过了三个,第四个re了。也一并给出做参考吧。
C++ AC
#include <stdio.h> #include <vector> #include <string.h> #include <stack> using namespace std; const int maxn = 100002; int dfn[maxn]; int low[maxn]; int visited[maxn]; int instack[maxn]; int groupId[maxn]; int groupNum[maxn]; stack<int> numStack; vector<int> edge[maxn],root[maxn]; int time,count,caseNum; int n,m,s; int min(int x, int y){ return x < y ? x : y; } int max(int x, int y){ return x > y ? x : y; } void initArr(){ time = 1; count = 0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(visited,0,sizeof(visited)); memset(instack,0,sizeof(instack)); memset(groupId,0,sizeof(groupId)); memset(groupNum,0,sizeof(groupNum)); while(!numStack.empty()){ numStack.pop(); } for(int i = 0; i < maxn; i++){ edge[i].clear(); root[i].clear(); } } void tarjan(int u){ dfn[u] = low[u] = time; time++; visited[u] = 1; instack[u] = 1; numStack.push(u); int size = edge[u].size(); for(int i = 0; i < size; i++){ int v = edge[u][i]; if(visited[v] == 0){ tarjan(v); low[u] = min(low[u],low[v]); }else if(instack[v] == 1){ low[u] = min(low[u],dfn[v]); } } if(dfn[u] == low[u]){ count++; while(true){ int v = numStack.top(); numStack.pop(); instack[v] = 0; groupId[v] = count; groupNum[count]++; if(v == u){ break; } } } } void buildRoot(){ for(int i = 1; i < n+1 ; i++){ if(visited[i] == 0){ continue; } int size = edge[i].size(); for(int j = 0 ; j < size; j++){ int v = edge[i][j]; if(groupId[v] != groupId[i]){ root[groupId[i]].push_back(groupId[v]); } } } } int dfs(int u){ int maxLen = 0; visited[u] = 1; int size = root[u].size(); for (int i = 0; i < size; i++) { int v = root[u][i]; if (visited[v] == 0) { int tempLen = dfs(v); maxLen = max(tempLen, maxLen); visited[v] = 0; } } return groupNum[u] + maxLen; } int main(){ caseNum = 1; while(scanf("%d%d%d",&n,&m,&s) != EOF){ initArr(); int i; for(i = 0; i < m; i ++){ int v,u; scanf("%d%d",&v,&u); edge[v].push_back(u); } tarjan(s); buildRoot(); memset(visited,0,sizeof(visited)); printf("Case %d:\n%d\n",caseNum,dfs(groupId[s])); caseNum++; } return 0; } /************************************************************** Problem: 1418 User: wangzhenqing Language: C++ Result: Accepted Time:620 ms Memory:11628 kb ****************************************************************/
Java RE
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.StreamTokenizer; import java.util.ArrayList; import java.util.List; import java.util.Stack; public class Main { /* * 1418 */ private static int dfn[],low[],visited[],instack[],groupId[],groupNum[],maxNum[]; private static List<Integer> edgeList[],rootList[]; private static Stack<Integer> stack; private static int time,cnt; public static void main(String[] args) throws Exception { StreamTokenizer st = new StreamTokenizer(new BufferedReader( new InputStreamReader(System.in))); int caseNum = 1; while (st.nextToken() != StreamTokenizer.TT_EOF) { int n = (int)st.nval; st.nextToken(); int m = (int)st.nval; st.nextToken(); int s = (int)st.nval; initArr(n); for (int i = 0; i < m; i++) { st.nextToken(); int v = (int)st.nval; st.nextToken(); int u = (int)st.nval; if (edgeList[v] == null) { edgeList[v] = new ArrayList<Integer>(); } edgeList[v].add(u); } tarjan(s); buildRoot(n); System.out.printf("Case %d:\n%d\n",caseNum,dfs(groupId[s])); caseNum++; } } private static void buildRoot(int n) { for (int i = 1; i < n+1; i++) { if (visited[i] == 0) { continue; } int size = 0; if (edgeList[i] != null) { size = edgeList[i].size(); } for (int j = 0; j < size; j++) { int v = edgeList[i].get(j); if (groupId[v] != groupId[i]) { if (rootList[groupId[i]] == null) { rootList[groupId[i]] = new ArrayList<Integer>(); } rootList[groupId[i]].add(groupId[v]); } } } } private static int dfs(int u){ if(maxNum[u] != 0){ return maxNum[u]; } int maxCnt = 0; int size = 0; if (rootList[u] != null) { size = rootList[u].size(); } for (int i = 0; i < size; i++) { int v = rootList[u].get(i); int tempLen = dfs(v); maxCnt = Math.max(maxCnt,tempLen); } return maxNum[u] = (maxCnt + groupNum[u]); } private static void initArr(int n) { dfn = new int[n+1]; low = new int[n+1]; visited = new int[n+1]; instack = new int[n+1]; edgeList = new ArrayList[n+1]; rootList = new ArrayList[n+1]; groupId = new int[n+1]; groupNum = new int[n+1]; maxNum = new int[n+1]; stack = new Stack<Integer>(); time = 1; cnt = 0; } private static void tarjan(int u) { dfn[u] = low[u] = time; time++; visited[u] = 1; instack[u] = 1; stack.push(u); int size = 0; if (edgeList[u] != null) { size = edgeList[u].size(); } for (int i = 0; i < size; i++) { int v = edgeList[u].get(i); if (visited[v] == 0) {//未被访问过 tarjan(v); low[u] = Math.min(low[u], low[v]); }else if (instack[v] == 1) { low[u] = Math.min(low[u], dfn[v]); } } if (dfn[u] == low[u]) { cnt++; while (true) { if (stack.isEmpty()) { break; } int v = stack.peek(); stack.pop(); instack[v] = 0; groupId[v] = cnt; groupNum[cnt]++; if (v == u) { break; } } } } } /************************************************************** Problem: 1418 User: wangzhenqing Language: Java Result: Runtime Error ****************************************************************/