NYOJ 426 && poj 1125 最短路 DFS 判断联通 SPFA

首先,题目可能有多组测试数据,每个测试数据的第一行为经纪人数量N(当N=0时,输入数据结束),
然后接下来N行描述第i(1<=i<=N)个经纪人与其他经纪人的关系(教你如何画图)。每行开头数字M为
该行对应的经纪人有多少个经纪人朋友(该节点的出度,可以为0),然后紧接着M对整数,每对整数表
示成a,b,则表明该经纪人向第a个经纪人传递信息需要b单位时间(即第i号结点到第a号结点的孤长为b)
,整张图为有向图,即弧Vij 可能不等于弧Vji(数据很明显,这里是废话)。当构图完毕后,求当从该
图中某点出发,将“消息”传播到整个经纪人网络的最小时间,输出这个经纪人号和最小时间。最小时
间的判定方式为——从这个经纪人(结点)出发,整个经纪人网络中最后一个人接到消息的时。如果有
一个或一个以上经纪人无论如何无法收到消息,输出“disjoint”(有关图的连通性,你们懂得,但
据其他同学说,POJ测试数据中不会有,就是说,你不判定,一样能过,题目数据够水的)。
poj 上的测试数据 Floyd都能过
 
 
//NYOJ 426
#include <stdio.h>
#include <string.h>

#define N 1002
#define M 100000
#define MAXTIME 100000
#define MOVE(x) (x=(x+1)%N)

int nodev[N],n;
int nodeu[M],data[M],next[M];

bool Build_Graph()
{
	int i,v,u,value,m,ind;

	scanf("%d",&n);
	if(n==0)	return false;

	memset(nodev,-1,sizeof(nodev)); ind=0;
	for(v=1;v<=n;v++)
	{
		scanf("%d",&m);
		for(i=1;i<=m;i++)
		{
			scanf("%d %d",&u,&value);
			ind++;
			next[ind]=nodev[v];
			nodeu[ind]=u;
			data[ind]=value;
			nodev[v]=ind;
		}
	}
	return true;
}

bool visited[N];
bool possible[N];
int stack[N],top;
void DFS(int v)
{
	int i,u;
	visited[v]=true;
	for(i=nodev[v];i!=-1;i=next[i])
	{
		u=nodeu[i];
		if(!visited[u])
			DFS(u);
	}
}
bool decision(int v)
{
	int i;
	bool flag=true;
	for(i=1;i<=n;i++)
	{
		if(!visited[i])
		{
			flag=false;
			break;
		}
	}
	if(!flag)
	{
		for(i=1;i<=n;i++)
		{
			if(visited[i])
				possible[i]=false;
		}
	}
	else
		stack[++top]=v;
	return flag;

}
bool is_Connection()
{
	int i,v;

	for(i=1;i<=n;i++)
	{
		visited[i]=false;
		possible[i]=true;
	}
	top=0;
	for(v=1;v<=n;v++)
	{
		if(possible[v])
		{
			DFS(v);
			decision(v);
			memset(visited,false,sizeof(visited));
		}
	}
	return bool(top);
}

int queue[N];
bool flag[N];
int time[N];
int start,mintime;
void SPFA(int s)
{
	int i,v,u,value,front,rear;

	for(i=1;i<=n;i++)	time[i]=MAXTIME;
	front=-1; rear=-1; time[s]=0;
	memset(flag,false,sizeof(flag));
	for(i=nodev[s];i!=-1;i=next[i])
	{
		u=nodeu[i]; value=data[i];
		time[u]=value;
		queue[MOVE(rear)]=u;
		flag[u]=true;
	}

	//while(front<rear)//这里!!!!!!!!!
	while(front!=rear)
	{
		v=queue[MOVE(front)];
		flag[v]=false;
		for(i=nodev[v];i!=-1;i=next[i])
		{
			u=nodeu[i]; value=data[i];
			if(time[v]+value<time[u])
			{
				time[u]=time[v]+value;
				if(!flag[u])
				{
					queue[MOVE(rear)]=u;
					flag[u]=true;
				}
			}
		}
	}

}
void solve()
{
	int s,i,v,temp;
	mintime=MAXTIME;
	for(v=1;v<=top;v++)
	{
		s=stack[v];
		SPFA(s);
		temp=0;
		for(i=1;i<=n;i++)
		{
			if(time[i]>temp)
				temp=time[i];
		}
		if(temp<mintime)
		{
			mintime=temp;
			start=s;
		}
	}
}

int main()
{
	while(1)
	{
		if(!Build_Graph()) break;
		if(is_Connection())
		{
			solve();
			printf("%d %d\n",start,mintime);
		}
		else
			printf("disjoint\n");
	}

	return 0;
}

                

poj 1125 有点水

Floyd

/*
经典水题floyd这道题重点在于找到从某一个源点出发的最短路
怎么找?可以找到从一个源点出发最长的时间,即是传递结束,
然后找最长的最短。当然会出现有些人没有传递到,但是这道
题的bug在于此,不会出现disjoint的情况。

*/
#include<iostream>
#include<cstring>
using namespace std;

#define inf 20
#define M 210

int dist[M][M];
int n;

void floyd()
{
    for(int k = 1;k <= n; k++)
        for(int i = 1;i <= n; i++)
            for(int j = 1;j <= n; j++)
                if(i != j && dist[i][j] > dist[i][k] + dist[k][j])
                    dist[i][j] = dist[i][k] + dist[k][j];

    int minlength = inf;
    int maxlength,pos;
    for(int i = 1;i <= n; i++){
        maxlength = 0;
        for(int j = 1;j <= n; j++)
            if(i != j && maxlength < dist[i][j])
                maxlength = dist[i][j];
        if(minlength > maxlength){
            minlength = maxlength;
            pos = i;
        }
    }
    cout<<pos<<" "<<minlength<<endl;;
}

int main()
{
    while(1){
        memset(dist,inf,sizeof(dist));

        cin>>n;

        if(!n)
            break;

        for(int i = 1;i <= n; i++){
            int n1;
            cin>>n1;
            for(int j = 1;j <= n1; j++){
                int p,t;
                cin>>p>>t;
                dist[i][p] = t;
            }
        }
        floyd();
    }
    return 0;
}



                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值