http://poj.org/problem?id=3114
题目大意:
n个间谍 他们之间传送信息需要一定的时间
一个联通分量里面的间谍属于一个国家,之间的信息传递不需要时间
然后问你从一个间谍传一个信息到另一个间谍那需要最少时间 也可能传不到
联通缩点+最短路
缩点所得到的新图 可能是因为有重边或是太稠密 用邻接表容易超时
基本步骤:
1,输入去重边
2,Tarjan缩点
3,重新调整缩点后间谍之间的信息传递时间
4,最短路
注意: 图有可能不完全连通
代码及其注释:
#include<iostream> #include<cstring> #include<stack> #include<cstdio> #include<math.h> #include<algorithm> #include<queue> using namespace std; const int M=1000000002; const int N=515; struct node { struct tt *next; }mem[N]; struct node1 { struct tt *next; }remem[N]; struct tt { struct tt *next; int j; }; bool in[N]; bool visited[N]; int deep; stack<int>str; int dfn[N]; int low[N]; int uppoint[N]; int time[N][N]; inline void build(int i,int j) { struct tt *t=new tt; t->j=j; t->next=mem[i].next; mem[i].next=t; } inline void Clearlist(int n) { for(int i=1;i<=n;++i) { mem[i].next=NULL; } } void Tarjan(int x)//缩点 { ++deep; dfn[x]=low[x]=deep; visited[x]=true; in[x]=true; str.push(x); struct tt *t=mem[x].next; while(t!=NULL) { if(visited[t->j]==false) { Tarjan(t->j); low[x]=min(low[x],low[t->j]); }else if(in[t->j]==true) { low[x]=min(low[x],dfn[t->j]); } t=t->next; } if(low[x]==dfn[x]) { while(str.top()!=x) { uppoint[str.top()]=x; in[str.top()]=false; str.pop(); } uppoint[str.top()]=x; in[str.top()]=false; str.pop(); } } void dfs(int x)//调整缩点后有用点之间的信息传递时间 { visited[x]=true; struct tt *t=mem[x].next; while(t!=NULL) { if(uppoint[x]!=uppoint[t->j]) { time[uppoint[x]][uppoint[t->j]]=min(time[uppoint[x]][uppoint[t->j]],time[x][t->j]); } if(!visited[t->j]) { dfs(t->j); } t=t->next; } } int mintime(int st,int nd,int n)//求最短路 { if(st==nd) return 0; int dist[N]; memset(visited,false,sizeof(visited)); for(int i=1;i<=n;++i) if(time[st][i]==-1) dist[i]=M; else dist[i]=time[st][i]; visited[st]=true; for(int w=1;w<n;++w) { int MIN=M;int k=-1; for(int i=1;i<=n;++i) { if(!visited[i]&&dist[i]<MIN) { MIN=dist[i];k=i; } } if(k==-1) break; if(k==nd) break; visited[k]=true; for(int i=1;i<=n;++i) { if(dist[i]>dist[k]+time[k][i]) dist[i]=dist[k]+time[k][i]; } } return dist[nd]; } int main() { int n,m,q; while(scanf("%d %d",&n,&m)!=EOF) { if(n==0&&m==0) break; for(int i=1;i<=n;++i)//初始化 { for(int j=i;j<=n;++j) time[i][j]=time[j][i]=M; } while(m--) { int i,j,k; scanf("%d %d %d",&i,&j,&k); if(time[i][j]>k)//去重边 time[i][j]=k; } for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) { if(time[i][j]!=M)//建原图 build(i,j); } } memset(dfn,-1,sizeof(dfn)); memset(visited,false,sizeof(visited)); memset(in,false,sizeof(in)); memset(uppoint,-1,sizeof(uppoint)); while(!str.empty()) str.pop(); deep=0; for(int i=1;i<=n;++i) { if(dfn[i]==-1)//因为图有可能不完全联通 Tarjan(i); } memset(visited,false,sizeof(visited)); for(int i=1;i<=n;++i) { if(!visited[i])//因为图有可能不完全联通 { dfs(i); } } for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) { if(i!=uppoint[i]||j!=uppoint[j])//处理一下非联通缩点之间的信息传递时间 time[i][j]=M; } } scanf("%d",&q); while(q--) { int i,j,k; scanf("%d %d",&i,&j); i=uppoint[i];j=uppoint[j]; k=mintime(i,j,n); if(k==M) printf("Nao e possivel entregar a carta\n"); else printf("%d\n",k); } printf("\n"); Clearlist(n); } return 0; }