您的位置:首页 > 其它

poj3114 强连通+最短路

2015-09-17 20:12 447 查看
题意:有 n 个城市,城市之间能够通过邮件或者电子邮件传递消息,已知 m 条邮件线路,每条线路代表 A 能送邮件到 B,并且花费 V 时间,如果几个城市之间能够相互邮件送达,那么他们就在同一个国家内,他们之间就能够通过电子邮件传递消息,花费 0 时间。有 k 个询问,每次询问从点 a 到点 b 传送消息,最少需要花费多少时间。

由于多个城市能够互相送邮件,那么就在同一国家,互相传递消息不需要花费,因此首先强连通缩点,然后再对每次询问求出解就行。我一开始认为强连通缩点后是有向无环图,直接 dfs 的话对于每个询问复杂度不会很大,但是结果T了,然后换成了每个询问求一次单源最短路,然后A掉了。

#include<stdio.h>
#include<string.h>
#include<stack>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int,int> pii;

const int maxn=505;
const int maxm=250005;
const int INF=0x3f3f3f3f;

int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2],val[2][maxm];
int n,t,scccnt;
int stx[maxn],low[maxn],scc[maxn];
int dis[maxn];
stack<int>S;

int min(int a,int b){return a<b?a:b;}

void init(){
memset(head,-1,sizeof(head));
size[0]=size[1]=0;
}

void add(int a,int b,int v,int c=0){
point[c][size[c]]=b;
nxt[c][size[c]]=head[c][a];
val[c][size[c]]=v;
head[c][a]=size[c]++;
}

struct cmp{                    //将优先队列改为小根堆
bool operator()(pii a,pii b){
return a.first>b.first;
}
};

void dij(int s,int t){            //传入出发点和到达点
int i;
priority_queue<pii,vector<pii>,cmp>q;
q.push(make_pair(0,s));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
while(!q.empty()){
pii u=q.top();
q.pop();
if(u.first>dis[u.second])continue;
for(i=head[1][u.second];~i;i=nxt[1][i]){
int j=point[1][i];
if(dis[j]>u.first+val[1][i]){
dis[j]=u.first+val[1][i];
q.push(make_pair(dis[j],j));
}
}
}
if(dis[t]==INF)printf("Nao e possivel entregar a carta\n");
else printf("%d\n",dis[t]);
}

void dfs(int s){
stx[s]=low[s]=++t;
S.push(s);
for(int i=head[0][s];~i;i=nxt[0][i]){
int j=point[0][i];
if(!stx[j]){
dfs(j);
low[s]=min(low[s],low[j]);
}
else if(!scc[j]){
low[s]=min(low[s],stx[j]);
}
}
if(low[s]==stx[s]){
scccnt++;
while(1){
int u=S.top();S.pop();
scc[u]=scccnt;
if(s==u)break;
}
}
}

void setscc(){
memset(stx,0,sizeof(stx));
memset(scc,0,sizeof(scc));
t=scccnt=0;
for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
for(int i=1;i<=n;++i){
for(int j=head[0][i];~j;j=nxt[0][j]){
int k=point[0][j];
if(scc[i]!=scc[k]){
add(scc[i],scc[k],val[0][j],1);
}
}
}
}

int main(){
int m;
while(scanf("%d",&n)!=EOF&&n){
scanf("%d",&m);
init();
while(m--){
int a,b,v;
scanf("%d%d%d",&a,&b,&v);
add(a,b,v);
}
setscc();
int k;
scanf("%d",&k);
while(k--){
int a,b;
scanf("%d%d",&a,&b);
if(scc[a]==scc[b])printf("0\n");
else{
dij(scc[a],scc[b]);
}
}
printf("\n");
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: