您的位置:首页 > 其它

POJ3177-Redundant Paths

2011-09-09 09:17 288 查看
[b]转载请注明出处:優YoU /article/1968985.html[/b]



大致题意:

为了保护放牧环境,避免牲畜过度啃咬同一个地方的草皮,牧场主决定利用不断迁移牲畜进行喂养的方法去保护牧草。然而牲畜在迁移过程中也会啃食路上的牧草,所以如果每次迁移都用同一条道路,那么该条道路同样会被啃咬过度而遭受破坏。

现在牧场主拥有F个农场,已知这些农场至少有一条路径连接起来(不一定是直接相连),但从某些农场去另外一些农场,至少有一条路可通行。为了保护道路上的牧草,农场主希望再建造若干条道路,使得每次迁移牲畜时,至少有2种迁移途径,避免重复走上次迁移的道路。已知当前有的R条道路,问农场主至少要新建造几条道路,才能满足要求?



解题思路:

“使得每次迁移牲畜时,至少有2种迁移途径,避免重复走上次迁移的道路。”就是说当吧F个农场看作点、路看作边构造一个无向图G时,图G不存在桥。



那么可以建立模型:

给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图。



这题是和POJ3352一模一样的题,只不过表述方式不同而已。

详细解题过程请参考我POJ3352的解题报告,有详细叙述。



传送门:

我的POJ3353解题报告:

/article/1968984.html



看完POJ3353的解题报告,再回来看看本题要注意的一些地方:

本题和3353最大的区别就是,3353保证了没有重边,而本题有重边。

而3353的解题报告已经说过,当两点之间出现重边时,就不可以利用Low值去划分【边双连通分量】了,因为此时不同Low值的两点可能属于同一个【边双连通分量】!



那么如何解决重边的问题?

1、 构造图G时把重边也考虑进来,然后在划分边双连通分量时先把桥删去,再划分,其中桥的一端的割点归入当前正在划分的边双连通分量。这个处理比较麻烦;

2、 在输入图G的边时,若出现重边,则不把重边放入图G,然后在划分边双连通分量时依然用Low划分。



两者相权,当然是第2种方法更好处理了。

其实用邻接矩阵去存储图G的同学,是无需考虑重边的问题的。

但是用邻接链表去存储图G的同学就不得不考虑了,因为基本上都是用头插入法在链表中插入边的,所以无法检测重边。而改用尾插入法,则可以在指针从链头移到链尾的同时,顺便加一个判断,出现重边则不再插入,否则插入到尾部。







//Memory Time 
//236K   16MS  

#include<iostream>
using namespace std;

class Node
{
public:
	int id;
	class Node* next;
	Node():id(0),next(0){}
};

class solve
{
public:
	solve(int f,int r):F(f),R(r)
	{
		Initial();			
		Input_Creat();
		Tarjan(1,-1);		//本题给定的图G为连通的,因此从任意节点开始搜索均可
		printf("%d\n",BCC_SP_D_E());
	}
	~solve()
	{
		delete[] DFN;
		delete[] Low;
		delete[] degree;

		EmptyList();
	}

	int min(int a,int b) const{return a<b?a:b;}

	void Initial(void);				//申请存储空间并初始化
	void Input_Creat(void);			//输入并创建图G
	void AddEdge(int a,int b);		//向链表插入边a<->b (尾插入法,避免重边)

	void Tarjan(int s,int father);	//计算Low[]数组,用于寻找所有边双连通分量
	int BCC_SP_D_E(void);			//把每个边双连通分量(BCC)构造为缩点(SP),并计算每个缩点的度数(D)
									//返回值为使得图G为双连通所需添加的最少的边(E)的数量

	void DelLink(Node* p);			//释放以p为表头的整条链
	void EmptyList(void);			//释放邻接链表

protected:

	int F;					//the number of islands
	int R;					//the number of roads
	Node** LinkHead;		//邻接链表表头

	int TimeStamp;			//(外部)时间戳
	int* DFN;				//DFN[u]: 结点u的搜索次序(时间戳)
	int* Low;				//Low[u]: 结点u或u的子树能够追溯到的最早的栈中结点的次序号

	int* degree;			//记录每个缩点的总度数
};

void solve::Initial(void)
{
	LinkHead=new Node*[F+1];
	for(int i=1;i<=F;i++)
		LinkHead[i]=0;

	TimeStamp=0;
	DFN=new int[F+1];
	Low=new int[F+1];
	memset(DFN,0,sizeof(int)*(F+1));
	memset(Low,0,sizeof(int)*(F+1));

	degree=new int[F+1];
	memset(degree,0,sizeof(int)*(F+1));

	return;
}

void solve::Input_Creat(void)
{
	int a,b;
	Node* tmp;
	for(int j=1;j<=R;j++)
	{
		scanf("%d %d",&a,&b);

		if(!LinkHead[a])
			LinkHead[a]=new Node;
		if(!LinkHead)
			LinkHead[b]=new Node;

		AddEdge(a,b);
	}
	return;
}

void solve::AddEdge(int a,int b)
{
	Node* pa=LinkHead[a];
	Node* p1=new Node;
	p1->id=b;

	while(pa->next)
	{
		pa=pa->next;
		if(pa->id==p1->id)	//出现重边,重边不插入链表
			return;
	}
	pa->next=p1;

	Node* pb=LinkHead[b];
	Node* p2=new Node;
	p2->id=a;

	while(pb->next)			//能执行到这里说明a<->b不是重边
		pb=pb->next;		//直接搜索到链表尾部插入
	pb->next=p2;

	return;
}

void solve::Tarjan(int s,int father)
{
	DFN[s]=Low[s]=++TimeStamp;
	for(Node* p=LinkHead[s]->next;p;p=p->next)
	{
		int t=p->id;
		if(t!=father && DFN[t]<DFN[s])
		{
			if(DFN[t]==0)			//s->t为树枝边
			{
				Tarjan(t,s);
				Low[s]=min(Low[s],Low[t]);
			}
			else					//s->t为后向边
			{
				Low[s]=min(Low[s],DFN[t]);
			}
		}
	}
	return;
}

int solve::BCC_SP_D_E(void)
{
	for(int i=1;i<=F;i++)
		if(LinkHead[i])
		{
			for(Node* p=LinkHead[i]->next;p;p=p->next)	//枚举图G中每两个连通的点i<->j
			{											//由于图G为无向图,则连通是双向的
				int j=p->id;
				if(Low[i]!=Low[j])		//图G中Low值相同的两个点必定在同一个边双连通分量(即同一个缩点)中
				{						//检查i、j是否不在同一个缩点中

					degree[Low[i]]++;	//结点i所在的缩点的度+1
					degree[Low[j]]++;	//结点j所在的缩点的度+1
				}
			}
		}
	
	int leave=0;			//记录总度数=1(叶子)的缩点
	for(int k=1;k<=F;k++)	//枚举各个缩点的度数D
		if(degree[k]/2==1)	//由于是无向图,因此每个缩点的度都重复计算了2次,除2后才是真实的度数
			leave++;

	return (leave+1)/2;		//将一棵树连成一个边双连通分量至少需要添加的边数=(叶子节点数+1)/2
}

void solve::DelLink(Node* p)
{
	if(p->next)
		p=p->next;
	delete[] p;
	return;
}

void solve::EmptyList(void)
{
	for(int i=1;i<=F;i++)
		if(LinkHead[i])
			DelLink(LinkHead[i]);
	return;
}

int main(void)
{
	int f,r;
	while(scanf("%d %d",&f,&r)!=EOF)
		solve poj3177(f,r);

	return 0;
}






[b]Sample Input

7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7

7 7
1 2
2 3
3 4
2 5
4 5
3 6
5 7

6 5
3 1
3 2
3 4
3 5
3 6

10 12
1 2
2 3
3 1
3 4
4 8
4 5
5 6
6 7
7 5
8 9
9 10
10 8

10 10
1 8
6 3
7 1
3 5
5 2
2 9
9 7
8 4
4 10
10 6

10 9
1 2
7 4
9 6
10 6
8 4
3 5
3 4
3 6
1 3

16 22
1 3
7 1
5 1
12 7
6 3
4 7
8 3
10 7
14 6
11 5
9 7
15 4
2 6
13 12
8 2
2 11
6 1
4 11
1 14
3 10
13 16
13 16

27 35
1 3
10 3
22 3
15 3
11 15
5 15
12 22
18 10
23 11
7 1
2 15
25 1
14 10
24 11
8 2
19 22
4 12
16 4
13 18
9 14
21 13
6 4
17 23
20 17
17 6
3 21
20 3
9 13
17 12
20 18
2 26
26 27
27 8
2 27
26 8

75 81
1 3
58 3
37 1
36 58
15 36
9 58
10 37
8 1
44 10
33 44
61 8
54 9
4 3
20 44
53 37
26 20
67 54
71 20
5 3
70 54
45 67
14 54
74 67
41 53
52 37
63 53
31 20
55 63
60 55
40 5
75 58
62 31
68 52
72 36
49 9
66 31
43 41
22 52
35 8
21 45
30 15
11 61
7 68
57 30
12 40
27 71
25 40
46 66
42 61
24 37
29 4
59 11
16 74
47 5
69 74
64 59
56 75
19 9
48 56
23 9
13 72
2 43
32 1
73 13
28 7
6 45
18 4
38 42
50 72
17 53
39 50
51 63
34 25
65 64
67 41
58 5
5 27
75 63
7 50
20 18
38 65

200 250
1 3
106 1
134 1
157 134
23 106
60 134
44 60
117 1
126 1
11 134
139 44
178 3
97 60
101 157
118 44
30 23
128 30
174 3
108 23
110 128
132 157
92 106
173 132
79 106
82 178
7 44
52 79
74 30
4 23
49 7
164 139
127 30
156 4
65 7
120 101
46 97
112 178
8 46
59 60
198 174
100 134
90 92
192 60
125 100
26 178
19 192
63 125
155 126
70 100
35 63
151 126
165 157
146 70
84 157
141 52
160 70
163 8
38 127
171 139
62 101
133 11
177 146
158 125
41 165
145 52
98 30
5 177
68 164
168 173
107 178
86 132
199 127
136 168
71 155
50 128
189 35
193 46
105 70
195 189
89 158
69 177
190 50
28 19
21 92
93 71
170 86
122 21
131 136
197 158
16 108
33 195
18 164
196 141
94 92
61 79
149 26
169 193
124 163
78 189
147 108
150 49
129 70
77 168
194 18
54 100
140 127
24 196
109 158
2 97
17 195
64 28
115 174
185 41
81 141
45 62
180 18
167 109
27 65
123 140
188 77
91 129
73 110
76 173
14 149
103 105
51 11
57 84
58 101
148 193
43 156
162 109
22 61
179 52
67 74
200 117
6 167
119 192
113 41
184 16
32 98
39 160
75 32
175 98
121 78
183 26
47 174
102 79
83 23
172 127
176 74
138 121
182 90
29 156
153 183
114 162
152 47
15 136
12 64
143 155
161 89
99 90
87 114
25 193
144 86
137 64
135 52
56 14
55 112
20 71
142 5
34 126
116 56
40 79
130 89
187 49
85 62
111 136
191 39
166 16
159 120
13 50
95 55
154 33
96 171
181 115
88 21
80 24
48 14
72 21
31 67
9 31
66 143
37 117
104 56
36 86
42 125
186 33
10 184
53 18
164 64
136 63
77 25
128 105
133 147
130 1
67 161
10 132
190 173
195 80
123 1
70 82
126 38
163 7
193 17
152 105
44 24
168 185
174 163
177 40
79 173
70 19
26 60
198 130
97 22
143 67
97 25
119 89
194 163
188 180
49 173
109 71
4 124
58 79
151 178
74 93
34 96
161 65
167 16
172 114
183 14
46 116
199 187
118 175
109 23
101 115
160 114
110 173
96 28
77 182
27 116

14 16
1 2
1 12
12 2
3 2
4 3
4 5
4 6
6 14
7 14
7 6
7 8
7 9
10 9
11 10
11 13
13 10
Sample Output
2
2
3
2
0
3
2
4
16
32
2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: