Redundant Paths
【题目描述】
现有F(1 <= F <= 5000)个牧场,任何两个牧场之间至少有一条路,但奶牛们至少需要两条。
给定现有的R(F-1 <= R <= 10000)条直接连接两个牧场的路,计算至少需要新建多少条直接连接两个牧场的路,才能使得任何两个牧场之间至少有两条独立的路(两条独立的路是指没有公共边的路)。
【输入描述】
第一行输入两个数F、R;
接下来R行,每行输入两个数,表示存在一条路直接连接这两个牧场。
【输出描述】
输出一个数,表示答案。
【输入样例】
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7
【输出样例】
2
【数据范围及提示】
样例如下:
1 2 3
+-----+-----+
| |
| |
6 +-----+-----+ 4
/ 5
/
/
7 +
分别在1号牧场和6号牧场、4号牧场和7号牧场之间建路:
1 2 3
+-----+-----+
| | |
| | |
6 +-----+-----+ 4
/ 5 |
/ |
/ |
7 +-------------
源代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node { int To,Next; }Edge[10001]; int N,M,Num,Number,i[5001],j[5001],Head[5001]; bool Map[5001][5001]; void Add(int t1,int t2) //边表。 { Edge[++Num].To=t2; Edge[Num].Next=Head[t1]; Head[t1]=Num; } void Tarjan(int T,int Father) //Tarjan改版。 { i[T]=j[T]=++Number; for (int a=Head[T];a;a=Edge[a].Next) { int t=Edge[a].To; if (!j[t]) { Tarjan(t,T); i[T]=min(i[T],i[t]); } else if (t!=Father) //无向图,不是直系父亲才符合条件。 i[T]=min(i[T],j[t]); } } void Solve() { int Ans(0),Sum[5001]={0}; for (int a=1;a<=N;a++) for (int b=Head[a];b;b=Edge[b].Next) { int t=Edge[b].To; if (i[t]!=i[a]) //不在一环之内便为桥。 Sum[i[a]]++; } for (int a=0;a<=N;a++) if (Sum[a]==1) //树度数为1的节点数统计。 Ans++; printf("%d\n",(Ans+1)>>1); //防止奇数。 } int main() { while (scanf("%d%d",&N,&M)!=EOF) { Num=Number=0; //这令人恶心的初始化,为什么POJ的题要多数据啊啊啊! memset(j,0,sizeof(j)); memset(Map,0,sizeof(Map)); memset(Head,0,sizeof(Head)); for (int a=0;a<M;a++) { int t1,t2; scanf("%d%d",&t1,&t2); if (!Map[t1][t2]) //各点之间只有一条直连边。 { Add(t1,t2); Add(t2,t1); Map[t1][t2]=Map[t2][t1]=true; } } Tarjan(1,1); Solve(); } return 0; } /* 解题思路: 题目中要求桥数,可以先找出图中的双连通分量,进行缩点,因为在双连通分量中,每个点都已经有两条路了。 这样就可以建成一个无环图,再找出其中度数为1的节点,数量/2即可。 如果只利用i[]进行环的判断则会出错,因为一个点可能在多个环内。 */