uva247----Floyd[1++]

https://vjudge.net/problem/UVA-247

题意:如果两个人互相打电话(直接或者间接),则说他们在同一个电话圈里。例如,a打给b,b打给c,c打给d,d打给a,则这四个人在同一个圈里;如果e打给f,而f不打给e,则不能推出e和f在同一个电话圈。输入n(n<=25)个人的m次电话,找出所有的电话圈。人名只包含字母,不超过25个字符,且不重复。

分析:本题一看就是求有向图的强连通分量问题。可以用tarjan解决。但是注意到数据比较小,还可以想到另外一个算法——floyd。在有向图中,有时不必关心路径的长度,只关心每两点之间是否有通路,则可以用1和0表示“连通”和“不连通”。这样,就可以用floyd解决了:dp[i][j]=dp[i][j]||(dp[i][k]&&dp[k][j])。这样的结果称为有向图的传递闭包(Transitive Closure)。
 

需要注意的地方:

1.变量每次都要初始化,比如vs刚才忘记了

2.必须严格按照输入输出,比如刚才忘了输出时候的逗号后面空格

3.思路要严谨,刚才养了输出时候的内循环判断cir【j】

Folyd模板可用!

#include<vector>
#include<algorithm>
#include<string>
#include<iostream>
#include<map>
#include<stdio.h>
#include<cstring>
using namespace std;
#define maxn  30

vector<string> vs;

struct Edge{
    int from,to,dist;
};

struct Floyd{
    int n,m;
    int d[maxn][maxn],p[maxn];

    vector<int> G[maxn];
    void init(int n)
    {
        this->n=n;
        for(int i=0;i<n;i++)
        {
        	memset(d[i],0,sizeof(d[i]));
        }
    }
    void AddEdge(int from,int to,int dist)
    {
        d[from][to]=dist;
        m++;

    }
    void floyd()
    {
         for(int k=0;k<n;k++)
           for(int i=0;i<n;i++)
             for(int j=0;j<n;j++)
             {
             	d[i][j]=d[i][j]||(d[i][k]&&d[k][j]);
             }
    }
    void print()
    {
   	     for(int i=0;i<n;i++)
           {
           	  for(int j=0;j<n;j++)
             {
             	cout<<d[i][j];
             }
             cout<<endl;
           }  
	   	
    }
};

int tofind(string s)
{   
    int i;
	for(i=0;i<vs.size();i++)
	{
		if(s==vs[i])
		{
			return i;
		}
	} 
	if(i==vs.size())
	{
		vs.push_back(s);
		return i;
	}
}
Floyd solver;
int main()
{
	int n,m,icount=1;;
	cin>>n>>m;
	while(!(!m&&!n))
	{
		solver.init(n);
		vs.clear();
		for(int i=0;i<m;i++)
		{
			string s1,s2;
			cin>>s1;
			cin>>s2;
			int i1=tofind(s1);
			int i2=tofind(s2);
			solver.AddEdge(i1,i2,1);
		}
		solver.floyd();
		//solver.print();
		int cir[maxn]={0};
		cout<<"Calling circles for data set "<<icount++<<":"<<endl;
		for(int i=0;i<n;i++)
		{
			if(cir[i]) continue;
			string s1=vs[i]+", ";
			for(int j=i+1;j<n;j++)
			{
				if(cir[j]) continue;
				if(solver.d[i][j]&&solver.d[j][i])
				{
				   s1+=vs[j]+", ";
				   cir[j]=1;
				}
			}
			cout<<s1.substr(0,s1.length()-2)<<endl;
		}
		cin>>n>>m;
		if(!(!m&&!n))
		cout<<endl;
		
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值