POJ 1523 SPF 解题报告

  思路:使用tarjan算法求出割点,在枚举去掉每一个割点所能形成的联通块的个数。

  注意:后来我看了下别的代码,发现我的枚举割点的方式是比较蠢的方式,我们完全可以在tarjan过程中把答案求出来,引入一下讨论:

  如果这个割点是根节点,在tarjan算法中搜到几个孩子结点(low[v] >= dfn[u]),他就能割出几个联通块,如果这个割点是孩子结点,那么他所形成的联通块的个数+1,因为他还有一条与父亲结点间接或直接相连的边。

  代码如下:

#include<map>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define maxn 1010
struct EDGE
{
    int to,nxt;
} edge[maxn*10];
int head[maxn],low[maxn],dfn[maxn],mark[maxn],vis[maxn];
int tot,all,son,start,tail;
void add_edge(int u,int v)
{
    edge[tot].to = v;
    edge[tot].nxt = head[u];
    head[u] = tot++;
}
void init()
{
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(mark,0,sizeof(mark));
    all = 0;
    son = 0;
}
void tarjan(int u,int fa)
{
    dfn[u] = low[u] = ++all;
    for(int i = head[u]; i != -1; i = edge[i].nxt)
    {
        int v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u] = min(low[v],low[u]);
            if(low[v] >= dfn[u])
            {
                if(u == start) son++;
                else mark[u] = 1;
            }
        }
        else if(v != fa) low[u] = min(low[u],dfn[v]);
    }
    return ;
}
void bfs(int x,int cant)
{
    queue<int>que;
    while(!que.empty()) que.pop();
    que.push(x);
    vis[x] = 1;
    while(!que.empty())
    {
        int num = que.front();
        que.pop();
        for(int i = head[num]; i != -1; i = edge[i].nxt)
        {
            int v = edge[i].to;
            if(v != cant && !vis[v])
            {
                que.push(v);
                vis[v] = 1;
            }
        }
    }
    return ;
}
int main()
{
    int a,b;
    int ca = 0;
    while(~scanf("%d",&a))
    {
        if(!a) break;
        start = 0,tail = 0;
        scanf("%d",&b);
        start = min(a,b);
        tail = max(a,b);
        tot = 0;
        memset(head,-1,sizeof(head));
        add_edge(a,b);
        add_edge(b,a);
        while(~scanf("%d",&a))
        {
            if(!a) break;
            scanf("%d",&b);
            add_edge(a,b);
            add_edge(b,a);
            start = min(min(a,b),start);
            tail = max(max(a,b),tail);
        }
        init();
        tarjan(start,-1);
        if(son >= 2) mark[start] = 1;
        int subnets = 0,spf = 0;
        printf("Network #%d\n",++ca);
        bool flag = true;
        for(int i = start; i <= tail; i++)
        {
            if(mark[i])
            {
                flag = false;
                printf("  SPF node %d leaves ",i);
                memset(vis,0,sizeof(vis));
                subnets = 0;
                for(int j = start;j <= tail;j++)
                {
                    if(j == i) continue;
                    if(!vis[j])
                    {
                        subnets++;
                        bfs(j,i);
                    }
                }
                printf("%d subnets\n",subnets);
            }
        }
        if(flag) puts("  No SPF nodes");
        puts("");
    }
    return 0;
}
时间: 2024-10-25 19:09:50

POJ 1523 SPF 解题报告的相关文章

poj 1469 COURSES 解题报告

题目链接:http://poj.org/problem?id=1469 题目意思:略 for 循环中遍历的对象要特别注意,究竟是遍历课程数P 还是 学生数N,不要搞混! 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn = 300 + 5; 7 int match[maxn], map[maxn][maxn];

poj 1258 Agri-Net 解题报告

题目链接:http://poj.org/problem?id=1258 题目意思:给出 n 个 farm,每个farm 之间通过一定数量的fiber 相连,问使得所有farm 直接或间接连通的 最少 fiber 数是多少. 赤裸裸的最小生成树,用prim做的. 有个地方写错,wa 了 几次. 1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 5 const int farm_num = 10000

poj 2923 Relocation 解题报告

题目链接:http://poj.org/problem?id=2923 题目意思:给出两部卡车能装的最大容量,还有n件物品的分别的weight.问以最优方式装入,最少能运送的次数是多少. 二进制表示物品状态:0表示没运走,1表示已被运走. 枚举出两辆车一趟可以运出的状态.由于物品是一趟一趟运出来的.所以就可以由一个状态通过两辆车一趟的状态转移到另一个状态. dp[i]=MIN(dp[k]+1).k可以由两车一趟转移到i. 我是参考此人的:http://blog.csdn.net/bossup/a

poj 2253 Frogger 解题报告

题目链接:http://poj.org/problem?id=2253 题目意思:找出从Freddy's stone  到  Fiona's stone  最短路中的最长路. 很拗口是吧,举个例子.对于 i 到 j 的一条路径,如果有一个点k, i 到 k 的距离 && k 到 j 的距离都小于 i 到 j 的距离,那么就用这两条中较大的一条来更新 i 到 j 的距离 .每两点之间都这样求出路径.最后输出 1 到 2 的距离(1:Freddy's stone   2:Fiona's sto

poj 1724 ROADS 解题报告

题目链接:http://poj.org/problem?id=1724 题目意思:给出一个含有N个点(编号从1~N).R条边的有向图.Bob 有 K 那么多的金钱,需要找一条从顶点1到顶点N的路径(每条边需要一定的花费),前提是这个总花费  <= K. 首先这里很感谢 yunyouxi0 ,也就是我们的ACM队长啦~~~,他一下子指出了我的错误——存储重边的错误.这条题卑鄙的地方是,有重边,discuss 中的数据过了也不一定会AC啦.大家不妨试试这组数据(队长深情奉献^_^) 2 2 2 1

POJ 1523 SPF(强连通分量求割点)

题目地址:POJ 1523 这题猛的一看..貌似有点难的样子.不过仔细一想,那个每个割点所分成一次子图不就都能找到这个割点一次吗,那么只要记录下它作为割点的次数再+1不就行了.也算是求割点的裸题吧.这个题的输出很坑...需要注意一下.. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #incl

poj 1523 SPF

SPF http://poj.org/problem?id=1523 Time Limit: 1000MS   Memory Limit: 10000K       Description Consider the two networks shown below. Assuming that data moves around these networks only between directly connected nodes on a peer-to-peer basis, a fail

【原创】poj ----- 1182 食物链 解题报告

题目地址: http://poj.org/problem?id=1182 题目内容: 食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 48791   Accepted: 14222 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个

POJ - 1523 SPF(割点)

题目大意:给出一张图,问去割点后,连通分量的个数有多少 解题思路:割点的水题,套模版就可以 不得不吐槽一下输入.. #include <cstdio> #include <cstring> #define min(a,b) ((a)<(b)?(a):(b)) #define N 1010 #define M 2000010 struct Edge{ int to, next; }E[M]; int head[N], num[N], pre[N], lowlink[N]; in