POJ 3114 Countries in War

http://poj.org/problem?id=3114

/* 题意是:给你一些城市,这些城市有些是同一个国家(如果在同一个国家,那么任何两个城市都可以到达---强联通分量),如果不在同一个国家,那么发送信息需要时间 一开始并没有给你哪些城市是同一个国家,你需要自己去判断,最后有些询问,问的是两个城市发送需要多少最短时间 考点:强联通+Dijkstra算法 */ #include<stdio.h> #include<string.h> const int N=510; const int maxint=0x03f3f3f3f; int low[N],dfn[N]; bool instack[N]; int edge[N][N]; int dist[N][N]; int stap[N]; int belong[N]; bool visited[N]; int stop,index,bcnt; int min(int a,int b) { return a<b?a:b; } void tarjan(int start,int n) { int i,j; low[start]=dfn[start]=++index; instack[start]=true; stap[++stop]=start; for(i=1;i<=n;i++) { if(edge[start][i]==maxint) continue; if(!dfn[i]) { tarjan(i,n); if(low[i]<low[start]) low[start]=low[i]; } else if(instack[i]&&dfn[i]<low[start]) low[start]=dfn[i]; } if(dfn[start]==low[start]) { bcnt++; do { j=stap[stop--]; instack[j]=false; belong[j]=bcnt; } while(start!=j); } } void recreate(int n) { int i,j,k; for(i=1;i<=bcnt;i++) for(j=1;j<=bcnt;j++) dist[i][j]=maxint; for(i=1;i<=n;i++) for(j=1;j<=n;j++) { if(edge[i][j]==maxint) continue; if(belong[i]!=belong[j]) dist[belong[i]][belong[j]]=min(dist[belong[i]][belong[j]],edge[i][j]); } } int lowcost[N],vis[N]; void dijkstra(int beg,int n) { int i,j,min; memset(vis,0,sizeof(vis)); vis[beg]=1; for(i=1;i<=n;i++) lowcost[i]=dist[beg][i]; lowcost[beg]=0; int pre=beg; for(i=2;i<=n;i++) { min=maxint; for(j=1;j<=n;j++) if(vis[j]==0&&lowcost[pre]+dist[pre][j]<lowcost[j]) lowcost[j]=lowcost[pre]+dist[pre][j]; for(j=1;j<=n;j++) if(vis[j]==0&&lowcost[j]<min) { min=lowcost[j]; pre=j; } vis[pre]=1; } } void solve(int n,int m) { int i,j,k; int x,y,h; memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(instack,0,sizeof(instack)); memset(stap,0,sizeof(stap)); memset(belong,0,sizeof(belong)); memset(visited,0,sizeof(visited)); for(i=1;i<=n;i++) for(j=1;j<=n;j++) edge[i][j]=maxint; stop=index=bcnt=0; for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&h); edge[x][y]=h; } for(i=1;i<=n;i++) if(!dfn[i]) tarjan(i,n); recreate(n); scanf("%d",&k); for(i=1;i<=k;i++) { scanf("%d%d",&x,&y); if(belong[x]==belong[y] && belong[x]!=0) printf("0/n"); else { if(visited[belong[x]]==false) dijkstra(belong[x],bcnt); if(lowcost[belong[y]]==maxint) printf("Nao e possivel entregar a carta/n"); else printf("%d/n",lowcost[belong[y]]); } } } int main() { int n,e; // freopen("in.txt","r",stdin); while(scanf("%d%d",&n,&e)!=EOF && n) { solve(n,e); printf("/n"); } return 0; }

/* 题意是:给你一些城市,这些城市有些是同一个国家(如果在同一个国家,那么任何两个城市都可以到达---强联通分量),如果不在同一个国家,那么发送信息需要时间 一开始并没有给你哪些城市是同一个国家,你需要自己去判断,最后有些询问,问的是两个城市发送需要多少最短时间 考点:强联通+Dijkstra算法 */ #include<stdio.h> #include<string.h> #include<vector> using namespace std; #define MAXN 1000 int map[MAXN][MAXN]; vector<int> graph[MAXN];//用来存放图的结构 int belong[MAXN];//用来存放所属的强联通分支 int dfn[MAXN], low[MAXN];//用来存放搜索的次序,low用来存放能回到父节点的最早节点 int stack[MAXN];//用来存放强联通分支 int N, E, K; int index, num, top; bool instack[MAXN], visit[MAXN];//标记是否在堆栈中 int cost[MAXN][MAXN];//建立新图的结构 int d[MAXN]; bool visit1[MAXN]; #define inf 1>>20 inline int min(int a, int b) { return a < b ? a : b; } void tarjan(int u)//求强连通分支 { int v; dfn[u] = low[u] = index++; stack[top++] = u; instack[u] = true; visit[u] = true; for(int i=0; i<graph[u].size(); i++) { v = graph[u][i]; if(!visit[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if(instack[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]) { ++num; belong[u] = num; do { v = stack[top--]; belong[v] = num; instack[v] = false; }while(u != v); } } void dijkstra(int s, int t)//求最短路径 { int i, j, k, min; for(i=1; i<=num; i++) { d[i] = cost[s][i]; // if(d[i] == 0) // d[i] = inf; visit1[i] = false; } d[s] = 0; visit1[s] = true; for(i=1; i<=num; i++) { min = inf; k = s; for(j=1; j<=num; j++) { if(!visit1[j] && min < d[j]) { min = d[j]; k = j; } } visit1[k] = true; for(j=1; j<=num; j++) { if(!visit1[j] && d[k] + cost[k][j] < d[j]) d[j] = d[k] + cost[k][j]; } } } int main() { // freopen("in.txt","r",stdin); int x, y, h, a, b, i, j; while(scanf("%d %d", &N, &E) != EOF) { if(N == 0 && E == 0) break; memset(map, 0, sizeof(map)); for(i=1; i<=N; i++) graph[i].clear(); memset(instack, 0, sizeof(instack)); index = top = num = 0; memset(visit, 0, sizeof(visit)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(stack, 0, sizeof(stack)); for(i=1; i<=E; i++) { scanf("%d %d %d", &x, &y, &h); map[x][y] = h; graph[x].push_back(y); } for(i=1; i<=N; i++) if(!visit[i]) tarjan(i); /* printf("%d/n", num); for(i=1; i<=N; i++) printf("%d %d/n", i, belong[i]);*/ memset(cost, 0, sizeof(cost)); for(i=1; i<=N; i++) for(j=1; j<=N; j++) { if(i==j) continue; if(belong[i] == belong[j]) continue; // printf("%d %d %d %d %d %d/n", i, j, map[i][j], belong[i], belong[j], cost[belong[i]][belong[j]]); if(cost[belong[i]][belong[j]] == 0)//如果不属于同一强连通分支 cost[belong[i]][belong[j]] = map[i][j]; if(map[i][j] != 0 && map[i][j] < cost[belong[i]][belong[j]])//如果当前还有更少时间的路径,则更新 cost[belong[i]][belong[j]] = map[i][j]; } for(i=1; i<=num; i++) for(j=1; j<=num; j++) { if(i==j) continue; if(cost[i][j] == 0) cost[i][j] = inf; } /* for(i=1; i<=num; i++) { for(j=1; j<=num; j++) { if(i == j) continue; printf("%d ", cost[i][j]); } printf("/n"); }*/ scanf("%d", &K); for(i=1; i<=K; i++) { scanf("%d %d", &a, &b); // printf("%d %d %d %d/n", a, b, belong[a], belong[b]); if(belong[a] == belong[b]) { printf("0/n"); continue; } dijkstra(belong[a], belong[b]); if(d[belong[b]] == inf) printf("Nao e possivel entregar a carta/n"); else printf("%d/n", d[belong[b]]); } printf("/n"); } return 0; }

 

你可能感兴趣的:(算法,Graph)