poj 3114 强连通+缩点+记忆化搜索
题意大致是这样的:在一个有向图里面,在同一个强连通分量里面的点之间的消费为0,不在同一个强连通分量的点之间是有消费的,问从一个点到另一个点的最小消费。
很显然在同一个强连通分量的点可以缩为一个点,然后重新构图结果肯定是一棵树。从始点到终点的最小消费可以用记忆化搜索来求解。
代码如下:
#include<iostream> #include<cstring> #include<stack> using namespace std; #define MAX_INT 1234567890 struct node { int v; int value; int next; }; stack <int> S; int pre[501],low[501],sc[501],cnt0,cnt1; int head1[501],head2[501],memory[501],n,N,M; node edge1[250001],edge2[250001]; int Tarjan(int i) { int j,min,e; pre[i]=cnt0++; low[i]=pre[i]; min=pre[i]; S.push(i); for(j=head1[i];j!=0;j=edge1[j].next) { if(pre[edge1[j].v]==-1) Tarjan(edge1[j].v); if(min>low[edge1[j].v]) min=low[edge1[j].v]; } if(min<low[i]) {low[i]=min; return 0;} do { e=S.top(),S.pop(); sc[e]=cnt1; low[e]=n; } while(e!=i); cnt1++; return 0; } int CGraph(int n) { int i,j; for(i=1;i<=n;i++) for(j=head1[i];j;j=edge1[j].next) if(sc[i]!=sc[edge1[j].v]) { node e={sc[edge1[j].v],edge1[j].value,0}; edge2[M]=e; edge2[M].next=head2[sc[i]]; head2[sc[i]]=M++; } return 0; } int dfs(int s,int t) { int i,k,min=MAX_INT; if(memory[s]) return memory[s]; if(s==t) return 0; for(i=head2[s];i;i=edge2[i].next) { k=dfs(edge2[i].v,t); min=(min>k+edge2[i].value) ? k+edge2[i].value:min; } memory[s]=min; return memory[s]; } int main() { int i,k,m,s,t,cost,start,end; while(scanf("%d%d",&n,&m)!=EOF && n) { N=M=1; memset(head1,0,sizeof(head1)); for(i=0;i<m;i++) { scanf("%d%d%d",&s,&t,&cost); node e={t,cost,0}; edge1[N]=e; edge1[N].next=head1[s]; head1[s]=N++; } for(i=1;i<=n;i++) pre[i]=-1; memset(sc,0,sizeof(sc)); for(cnt0=cnt1=1,i=1;i<=n;i++) if(pre[i]==-1) Tarjan(i); memset(head2,0,sizeof(head2)); CGraph(n); memset(memory,0,sizeof(memory)); cin>>k; while(k--) { cin>>start>>end; memset(memory,0,sizeof(memory)); if(sc[start]==sc[end]) { cout<<"0"<<endl; continue; } s=dfs(sc[start],sc[end]); if(s>=MAX_INT) cout<<"Nao e possivel entregar a carta"<<endl; else cout<<s<<endl; } cout<<endl; } return 0; }