--uva247(calling circles)强联通与floyd-warshell

图论题:一开始我是用tarjan算法做的,wrong answer 了很多次,然后又用了floyd-warshell算法,也wa了

最后找了题解,原来最后的dataset后面不是组数,是样例的编号,题根本就没说,让人怎么理解。。。

tarjan

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<map>
#include<algorithm>
#define M 100
using namespace std;

int qis;
int maps[50][50];
int dfn[M],low[M],vis[M],stacks[M];
int belongs[25][50];
int cnt ,scnt,begin,ans;

void init(){
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(stacks,0,sizeof(stacks));
    memset(vis,0,sizeof(vis));
    memset(belongs,0,sizeof(belongs));
    memset(maps,0,sizeof(maps));
    qis  = cnt = scnt =  begin  = ans =0;
}

void tarjan(int x){
    int v;
    dfn[x] = low [x] = ++cnt ;
    stacks[++begin] = x;
    for(int i = 1;i<=qis;i++){
        if(maps[x][i]){

            if(!dfn[i]){
                tarjan(i);
                low[x] = min(low[x],low[i]);
            }
            else if(!vis[i]){
                low[x] = min(low[x],dfn[i]);
            }

        }
    }
    if(low[x] == dfn[x]){
        scnt ++;
        do{
            v = stacks[begin--];
            belongs[scnt][++belongs[scnt][0]] = v;//顶点处理
            vis[v] = 1;
        }while(v != x);

        if(belongs[scnt][0]>1)ans ++;

    }
}

int main(){
    int flag = 1;
    int n,m;
    int cases = 1;
    while(scanf("%d%d",&n,&m),n||m){

        string a,b;

        init();

        map<string,int>ms;
        map<int,string>_ms;
        ms.clear();_ms.clear();

        for(int i = 0;i<m;i++){

           cin>>a>>b;
           if(ms[a] == 0)ms[a] = ++qis;
           if(ms[b] == 0)ms[b] = ++qis;
           _ms[ms[a]] = a;
           _ms[ms[b]] = b;
           maps[ms[a]][ms[b]] = 1;

        }

        for(int i  =1;i<= qis;i++){

            if(!dfn[i])tarjan(i);

        }
        if(flag == 1)flag = 0;
        else puts("");

        printf("Calling circles for data set %d:\n",cases++);
        for(int i = 1;i<=scnt;i++){
            int j;
            for(j = 1;j<belongs[i][0];j++)
               cout<<_ms[belongs[i][j]]<<", ";
            cout<<_ms[belongs[i][j]]<<endl;
        }

    }
}

floyd-warshell:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<map>
#include<algorithm>
#define M 100
using namespace std;

int qis;
int maps[50][50];
int vis[M];
int belongs[25][50];
int scnt ,ans;
int cases = 1;

int main(){
    int flag = 1;
    int n,m;
    while(scanf("%d%d",&n,&m),n||m){
        qis =ans =  scnt = 0;
        string a,b;
        map<string,int>ms;
        map<int,string>_ms;
        ms.clear();_ms.clear();
        memset(vis,0,sizeof(vis));
        memset(maps,0,sizeof(maps));
        memset(belongs,0,sizeof(belongs));
        for(int i = 1;i<=n;i++)maps[i][i] = 1;
        for(int i = 0;i<m;i++){

           cin>>a>>b;
           if(ms[a] == 0)ms[a] = ++qis;
           if(ms[b] == 0)ms[b] = ++qis;
           _ms[ms[a]] = a;
           _ms[ms[b]] = b;
           maps[ms[a]][ms[b]] = 1;

        }

        //floyd
		for(int k = 1;k <= n;k++)
		    for(int i = 1;i <= n;i++)
			    for(int j = 1;j <= n;j++){

    				maps[i][j] = maps[i][j] || (maps[i][k] && maps[k][j]);

    			} 

		for(int i = 1;i<=n;i++){
			if(vis[i] == 0){
				scnt++;
				for(int j = 1;j<=n;j++){

					if(maps[i][j]&&maps[j][i]){
							belongs[scnt][++belongs[scnt][0]] = j;
							vis[j] = 1;
					}

				}
				if(belongs[scnt][0]>1)ans++;
			}

		}
        if(flag == 1)flag = 0;
        else puts("");

        printf("Calling circles for data set %d:\n",cases++);
        for(int i = 1;i<=scnt;i++){
            int j;
            for(j = 1;j<belongs[i][0];j++)
               cout<<_ms[belongs[i][j]]<<", ";
            cout<<_ms[belongs[i][j]]<<endl;
        }

    }
}

  

时间: 2024-08-26 15:09:17

--uva247(calling circles)强联通与floyd-warshell的相关文章

UVa247 Calling Circles (Floyd,DFS)

链接:http://bak3.vjudge.net/problem/UVA-247 分析:先用Floyd求出有向图的传递闭包,然后用DFS求出各个联通分量即可. 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <string> 5 using namespace std; 6 7 vector<string> names; 8 int ID(const

【UVA】247 - Calling Circles(floyd判断包闭,dfs输出)

最近状态不佳,总是爱犯低级错误,比较水的题,没什么需要讲得,要说的可能是floyd判断包闭吧 void Floyd() { for(int k=1; k<=n; k++) for(int i=1; i<=n; i++) if(map[i][k]) for(int j=1; j<=n; j++) if(map[k][j]) map[i][j] = 1; } 之前做了不少图论,图论周感觉能应付的过去. 14059727 247 Calling Circles Accepted C++ 0.0

247 - Calling Circles (Floyd 求传递闭包)

该题恰好用到刚刚讲到的Floyd求传递闭包 , 因为该题的数据量不是很大, 要是大了估计就要用其他方法了 .  但是这毕竟是一个很简单易写的算法 . 求出传递闭包之后就用并查集将在一个电话圈的人合并在一起,最后输出 . 细节参见代码: #include<bits/stdc++.h> using namespace std; int n,m,d[30][30],par[30],kase = 0; string s1,s2; map<string , int > p; map<i

uva 247 Calling Circles(Floyd 的简单应用)

最近在看图论的经典算法, 先看的是求单源最短路的dijkstra,优化后的算法用了优先队列,看起来有点复杂. 感觉 弗洛伊德(Floyd) 要比 迪克斯特拉(dijkstra) 更好理解一点,但是Floyd是三层循环,当然会慢很多.一旦数据开大就跪了吧. floyd可以用来求 两个 连通点间的最短路问题.同时可以得到边权的和,即最短路的长度. 另外一个比较简单的应用,还可以用来判断两点间的连通性.即判断两点是否连通.本题就是弗洛伊德的这种简单用法. #include<cstdio> #incl

UVa 247 - Calling Circles(Floyd求有向图的传递闭包)

链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=183 题意: 如果两个人相互打电话(直接或间接),则说他们在同一个电话圈里.例如,a打给b,b打给c,c打给d,d打给a,则这4个人在同一个圈里:如果e打给f但f不打给e,则不能推出e和f在同一个电话圈里.输入n(n≤25)个人的m次电话,找出所有电话圈.人名只包含字母,不超过25个

11.3.4 例题11-4 UVA 247 Calling Circles (有向图的传递闭包)

题目大意: 给你n个人,m条边,a->b,b->a,才能说这两个人是联通的.问现在有多少个联通圈.输出每个联通圈.n<=25 解题思路: 直接建图,用有向图的闭包传递特性来处理每个人之间的联通关系.然后dfs一次,遍历邻接矩阵中与某个点相连的几个点,边遍历, 边打印输出. 代码: # include<cstdio> # include<iostream> # include<map> # include<cstring> # include

UVa 247 Calling Circles【传递闭包】

题意:给出n个人的m次电话,问最后构成多少个环,找出所有的环 自己想的是:用map来储存人名,每个人名映射成一个数字编号,再用并查集,求出有多少块连通块,输出 可是map不熟,写不出来,而且用并查集输出的时候感觉貌似很麻烦 然后再用的传递闭包,可是判断到d[i][j]==1和d[j][i]==1,该怎么输出路径呢 于是看了lrj的代码= = 用的是一个ID(string s)函数来给名字编号,和第五章的集合栈计算机那题的办法一样 然后用dfs输出路径= =(这个要好好--好好--好好学) 最后还

POJ 2186 Popular cows(Kosaraju+强联通分量模板)

题目链接:http://poj.org/problem?id=2186 题目大意:给定N头牛和M个有序对(A,B),(A,B)表示A牛认为B牛是红人,该关系具有传递性,如果牛A认为牛B是红人,牛B认为牛C是红人,那么牛A也认为牛C是红人.求被其他所有牛认为是红牛的牛的总数. 解题思路:把所有牛看成顶点,把有序对(A,B)看成从A到B的有向边,那么题目就变成了求所有顶点都可到达的顶点的总数.我们可以得到一个结论,如果一个强连通分量里有一头牛被认为是红人,那么该强联通分量里的所有牛都是红人,这显然是

Light OJ 1034 - Hit the Light Switches(强联通分量)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1034 题目大意:有n盏灯,有m个关系, 关系a,b表示如果a灯开关打开那么b灯也会亮起来, 现在求至少需要打开多少开关使所有灯都亮. 题目思路:先由强联通分量缩点, 得到DAG图, 然后根据DAG图,求出有多少入度为0的点, 即为所求. 代码如下: #include<bits/stdc++.h> using namespace std; const int N = 1000