首页 > 代码库 > poj——3177Redundant Paths
poj——3177Redundant Paths
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 15272 | Accepted: 6436 |
Description
Given a description of the current set of R (F-1 <= R <= 10,000) paths that each connect exactly two different fields, determine the minimum number of new paths (each of which connects exactly two fields) that must be built so that there are at least two separate routes between any pair of fields. Routes are considered separate if they use none of the same paths, even if they visit the same intermediate field along the way.
There might already be more than one paths between the same pair of fields, and you may also build a new path that connects the same fields as some other path.
Input
Lines 2..R+1: Each line contains two space-separated integers which are the fields at the endpoints of some path.
Output
Sample Input
7 71 22 33 42 54 55 65 7
Sample Output
2
Hint
One visualization of the paths is:
1 2 3Building new paths from 1 to 6 and from 4 to 7 satisfies the conditions.
+---+---+
| |
| |
6 +---+---+ 4
/ 5
/
/
7 +
1 2 3Check some of the routes:
+---+---+
: | |
: | |
6 +---+---+ 4
/ 5 :
/ :
/ :
7 + - - - -
1 – 2: 1 –> 2 and 1 –> 6 –> 5 –> 2
1 – 4: 1 –> 2 –> 3 –> 4 and 1 –> 6 –> 5 –> 4
3 – 7: 3 –> 4 –> 7 and 3 –> 2 –> 5 –> 7
Every pair of fields is, in fact, connected by two routes.
It‘s possible that adding some other path will also solve the problem (like one from 6 to 7). Adding two paths, however, is the minimum.
Source
描述
为了从一个F(1=f=5000)放牧场(编号为1…F)到另一个场,Bessie和其他牧群被迫越过腐烂的苹果树附近。奶牛现在已经厌倦了常常被迫走一条特定的道路,并且想建立一些新的道路,这样他们就可以在任何一对田地之间选择至少两条独立的路线。他们目前至少有一对路线之间的每一对领域,并希望有至少两个。当然,当他们从一个领域迁移到另一个领域时,他们只能在正式的道路上旅行。
描述了R的电流设定(F-1 <= R <= 10000),每个连接两个不同领域的路径,确定新的路径的最小数目(每个连接两个领域),必须建立,至少有两个独立的路线,任何对田野之间。如果路径没有相同的路径,即使它们在同一个中间区域访问相同的路径,它们也被认为是独立的。
在同一对字段之间可能有不止一条路径,您还可以构建一个新路径,将同一字段与其他路径连接起来。
输入
第1行:两个空间分隔的整数:f和r
第2行…r + 1:每行包含两个空间分隔的整数,这是某个路径端点的字段。
输出
第1行:一个整数,这是必须建立的新路径的数量。
思路:
我们来考虑一下这道题的做法。
由于题目说,给定一张无向强连通图:判断至少需要加多少条边,使得任意两点之间至少有两条相互‘边独立’的道路,也就是说,至少加多少条边,使得这个图成为一个边双连通图。
什么是双连通图?!
双连通图分为两种:双边连通图与双点连通图,双边连通图就是不存在割边的连通图,点双联通图就是不存在割点的连通图。。(差不多是这样吧。。)
首先我们已经有了一个连通图,我们先判断这个强连通图中是否存在环,这个就与tarjan缩点(有向图时有一点差别了)这个图保证是一个强连通图,如果我们还按以前那样缩点的话,我们只会把这个图个缩成一个点,这样肯定不对啊。。。
我们在缩完点以后把它变成了一个树,这样我们只需要把它的子节点连通起来就好了
也就是说:加入的边的条数一定等于:(叶子节点数+1)/2
我们在这个地方所说的叶子结点为入读或出度为0的点。
但在这里我又想到令一种算法:我们可以先求割边,割边的条数就是我们要求的叶子结点的个数
这样说有人可能会不明白了,那好,我们来看一个图
对于这个图来说,我们先将这个图中存在的环缩成一个点,那它就变成了右图的样子
在这里,我们以环缩点后的点5为根节点
看这个图的子节点是不是3?!
我们下面再来看看这个图的割边各大佬应该都能看出来我用红线割掉的边是这个图的割边吧。
他割边的个数是不是也是三?! 也就是说我们上面的结论成立。
那么这个题就变成一个很裸的求割边的板子了。。
好我们来看看代码吧。。
代码:(然而这个思路只能得63分,为什么?!)我们来考虑一下上面的思路的错误所在。
#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#define N 5005using namespace std;bool vis[N][N];long long n,m,x,y,ans,tot=1,tim;long long dfn[N],low[N];long long head[20010],cut_edge[20010];int read(){ int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) f=-1; ch=getchar();} while(ch<=‘9‘&&ch>=‘0‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f;}struct Edge{ int from,next,to;}edge[20010];void add(int x,int y){ tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot;}int tarjan(int now,int pre){ int sum=0; dfn[now]=low[now]=++tim; for(int i=head[now];i;i=edge[i].next) { if(i==(1^pre)) continue; int t=edge[i].to; if(!dfn[t]) { tarjan(t,i); low[now]=min(low[now],low[t]); if(low[t]>dfn[now]) cut_edge[i/2]=1; } else low[now]=min(low[now],dfn[t]); }}int main(){ n=read(),m=read(); for(int i=1;i<=m;i++) { x=read(),y=read(); if(!vis[x][y]&&!vis[y][x]) add(x,y),add(y,x); vis[x][y]=vis[y][x]=true; } tarjan(1,0); for(int i=1;i<=m;i++) if(cut_edge[i]==1) ans++; ///printf("%d\n",ans); printf("%d",(ans+1)>>1); return 0;}
样例的图有些不是很明显,我们来看另一个图
对于这样一个图的话:我们缩点之后把它变成了这样一个图:
这个图割边的条数为:5条,如果按照我们刚刚的结论来看的话,我们要添3条边,然而我们只需要添2条边就可以了
为什么?!
看这个图: 我们只需要在7~9,1~9之间添一条边就可以了。
那么我们还是乖乖地统计入读为2的点的个数吧。。。。。。(其实这个地方应该是度数为一的点,但是这个地方由于我们建的是双向边,每一个点都会统计两次,所以这个地方最小的将会是入读为2)
这个地方肯定有人就会问这样一个问题:为什么这个地方建的是双向边我们还能用tarjan缩点啊?! 缩点的时候所得不是一个强连通分量吗??这样的一个绝对联通的无向图不就是直接把他缩成了一个点了吗?!这样怎么还能这样做?!
想一下这个地方我们在缩点的时候为什么可以用tarjan??
这样缩点主要是归功于这一句话:if(i==(1^pre)) continue; 对,他是用两条边,但是我们这个地方只让他走一条边,这样不就和有向图缩点一样了吗?!
代码:
#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#define N 5005using namespace std;bool vis[N];long long n,m,x,y,ans,tot=1,tim,sum,top;long long du[N],dfn[N],low[N],stack[N],belong[N];long long head[20010];int read(){ int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) f=-1; ch=getchar();} while(ch<=‘9‘&&ch>=‘0‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f;}struct Edge{ int from,next,to;}edge[20010];void add(int x,int y){ tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot;}int tarjan(int now,int pre){ dfn[now]=low[now]=++tim; stack[++top]=now; for(int i=head[now];i;i=edge[i].next) { int t=edge[i].to; if(i==(1^pre)) continue; if(!dfn[t]) tarjan(t,i),low[now]=min(low[now],low[t]); else low[now]=min(low[now],dfn[t]); } if(low[now]==dfn[now]) { sum++; belong[now]=sum; for(;stack[top]!=now;top--) belong[stack[top]]=sum; top--; }}int main(){ n=read(),m=read(); for(int i=1;i<=m;i++) x=read(),y=read(),add(x,y),add(y,x); tarjan(1,0); for(int i=1;i<=n;i++) for(int j=head[i];j;j=edge[j].next) if(belong[i]!=belong[edge[j].to]) du[belong[i]]++,du[belong[edge[j].to]]++; for(int i=1;i<=n;i++) if(du[i]==2) ans++; printf("%d",(ans+1)>>1); return 0;}
输入样例: 输出:32
200 2501 3106 1134 1157 13423 10660 13444 60117 1126 111 134139 44178 397 60101 157118 4430 23128 30174 3108 23110 128132 15792 106173 13279 10682 1787 4452 7974 304 2349 7164 139127 30156 465 7120 10146 97112 1788 4659 60198 174100 13490 92192 60125 10026 17819 19263 125155 12670 10035 63151 126165 157146 7084 157141 52160 70163 838 127171 13962 101133 11177 146158 12541 165145 5298 305 17768 164168 173107 17886 132199 127136 16871 15550 128189 35193 46105 70195 18989 15869 177190 5028 1921 9293 71170 86122 21131 136197 15816 10833 19518 164196 14194 9261 79149 26169 193124 16378 189147 108150 49129 7077 168194 1854 100140 12724 196109 1582 9717 19564 28115 174185 4181 14145 62180 18167 10927 65123 140188 7791 12973 11076 17314 149103 10551 1157 8458 101148 19343 156162 10922 61179 5267 74200 1176 167119 192113 41184 1632 9839 16075 32175 98121 78183 2647 174102 7983 23172 127176 74138 121182 9029 156153 183114 162152 4715 13612 64143 155161 8999 9087 11425 193144 86137 64135 5256 1455 11220 71142 534 126116 5640 79130 89187 4985 62111 136191 39166 16159 12013 5095 55154 3396 171181 11588 2180 2448 1472 2131 679 3166 14337 117104 5636 8642 125186 3310 18453 18164 64136 6377 25128 105133 147130 167 16110 132190 173195 80123 170 82126 38163 7193 17152 10544 24168 185174 163177 4079 17370 1926 60198 13097 22143 6797 25119 89194 163188 18049 173109 714 12458 79151 17874 9334 96161 65167 16172 114183 1446 116199 187118 175109 23101 115160 114110 17396 2877 18227 116
poj——3177Redundant Paths