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;
}
posted @ 2011-08-10 19:51  书山有路,学海无涯  阅读(481)  评论(0编辑  收藏  举报