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;
}
浙公网安备 33010602011771号