大意:
农夫布朗的牧场上的篱笆已经失去控制了。它们分成了1~200英尺长的线段。只有在线段的端点处才能连接两个线段,有时给定的一个端点上会有两个以上的篱笆。结果篱笆形成了一张网分割了布朗的牧场。布朗想将牧场恢复原样,出于这个考虑,他首先得知道牧场上哪一块区域的周长最小。
布朗将他的每段篱笆从1到N进行了标号(N=线段的总数)。他知道每段篱笆的有如下属性:
- 该段篱笆的长度
- 该段篱笆的一端所连接的另一段篱笆的标号
- 该段篱笆的另一端所连接的另一段篱笆的标号
幸运的是,没有篱笆连接它自身。对于一组有关篱笆如何分割牧场的数据,写一个程序来计算出所有分割出的区域中最小的周长。
1
+---------------+
|\ /|
2| \7 / |
| \ / |
+---+ / |6
| 8 \ /10 |
3| \9 / |
| \ / |
+-------+-------+
4 5
分析与实现
原题给出的是图的对偶图,能在不复原原图的情况下求得环路吗?一开始想到在深度优先搜索中任意到已访问过的边都构成环路,就想当然的实现了。结果测试发现不对。于是实现了将对偶图复原成原图在顶点图上同样的算法,依然不正确。才想起来反省思路是否正确。的确不对,即使是对每个顶点都做一次深搜,也不能保证得到最小环,原因:有的环需要多于1条回边。因此,从设计思路来说,这样想,无法得到正确的结果。
于是换个角度考虑,既然已经得到了原图,那么,每次将一个顶点按其邻接边拆分成对应的不相邻顶点,这些顶点之间的最短路径,即为原图中的环。考虑到这个图本身稀疏的,用Bellman_Ford_SPFA对新生成的顶点各执行一次即可。这样,算法的总复杂度为DE,D为顶度数之和,E为边数。可以接受。
实现时注意两点:
1. 从对偶图得到正确的原图。这需要两次扫描。
2. 如何用最小的代价构造新图。不需要拷贝,只需要修改涉及的边,并在邻接表缓存的尾部增加相应的边即可。
/* ID: blackco3 TASK: fence6 LANG: C++ */ #include <iostream> #include <memory.h> using namespace std; const int _max_path_(200), _max_vex_(_max_path_<<1), _max_int_(0x7fffffff); struct t_path{ int dis, v[2], n_adj[2], adj[2][_max_path_] ; } pathes[_max_path_+1] ; struct t_adj { int to, dis ; t_adj( int t=0, int d=0 ) : to(t), dis(d) {} ; } adj_buf[_max_path_<<1], *p_adj_end ; struct t_vex { int n_adj ; t_adj *adj ; } vexes[_max_vex_]; int n_path(0), n_vex(0) ; int sdis[_max_vex_], queue[_max_vex_], in_que[_max_vex_] ; void Bellman_Ford_SPFA( int source, int n_add_on ){ memset( sdis, 0x7f, sizeof(int)*(n_vex+n_add_on) ); memset( in_que, 0, sizeof(int)*(n_vex+n_add_on) ) ; int *head=queue, *tail=queue; sdis[source]=0 , in_que[source]=1, *(tail++)=source ; do{ register int cvex= *head ; in_que[cvex]=0, head = (head-queue)==_max_vex_-1 ? queue : head+1; for( t_adj *p_adj=vexes[cvex].adj; p_adj!=vexes[cvex].adj+vexes[cvex].n_adj; p_adj++ ){ if( p_adj->dis + sdis[cvex] >= sdis[p_adj->to] ) continue ; sdis[p_adj->to] = p_adj->dis + sdis[cvex] ; if( !in_que[p_adj->to] ){ *tail=p_adj->to , in_que[p_adj->to]=1 ; tail = (tail-queue)==_max_vex_-1 ? queue : tail+1; } } }while( head!=tail ); } void build_graph( ){ memset( vexes, 0, sizeof(t_vex)*n_vex ) ; for( t_path *pc=pathes+1; pc!=pathes+n_path+1; pc++ ){ vexes[pc->v[0]].n_adj++, vexes[pc->v[1]].n_adj++ ; printf("Edge %d : <%d,%d> \n", pc-pathes, pc->v[0], pc->v[1]) ; } t_adj *p_adj=adj_buf; for( int i=0; i<n_vex; i++ ) vexes[i].adj=p_adj, p_adj+=vexes[i].n_adj, vexes[i].n_adj=0 ; p_adj_end = p_adj ; for( t_path *pc=pathes+1; pc!=pathes+n_path+1; pc++ ){ int v1=pc->v[0], v2=pc->v[1], dis=pc->dis ; vexes[v1].adj[ vexes[v1].n_adj++ ]=t_adj(v2,dis); vexes[v2].adj[ vexes[v2].n_adj++ ]=t_adj(v1,dis); } } void analysis_path( ) { cin >> n_path ; for( int i=0; i<n_path; i++){ int id ; cin >> id ; cin >> pathes[id].dis >> pathes[id].n_adj[0] >> pathes[id].n_adj[1] ; for( int j=0; j < pathes[id].n_adj[0] ; j++ ) cin >> pathes[id].adj[0][j] ; for( int j=0; j < pathes[id].n_adj[1] ; j++ ) cin >> pathes[id].adj[1][j] ; pathes[id].v[0] = pathes[id].v[1] = -1 ; } for( int ie=1; ie<=n_path; ie++ ){ for( int in=0; in<2; in++ ){ if( pathes[ie].v[in]!=-1 ) continue ; pathes[ie].v[in] = n_vex ; for( int ic=0; ic<pathes[ie].n_adj[in]; ic++ ){ int ie_con = pathes[ie].adj[in][ic], found = 0 ; for( int iadj=0; iadj<pathes[ie_con].n_adj[0]; iadj++ ){ if( pathes[ie_con].adj[0][iadj]==ie ){ found = 1, pathes[ie_con].v[0] = n_vex ; break ; } if( !found ) pathes[ie_con].v[1] = n_vex ; } } n_vex++ ; } } } void show_graph( int more=0 ){ for( int i=0; i<n_vex+more; i++ ){ printf("[%d]ADJ %d : ", i, vexes[i].n_adj); for( int j=0; j<vexes[i].n_adj; j++ ) printf("%d[%d] ", vexes[i].adj[j].to, vexes[i].adj[j].dis ); printf("\n"); } printf("-------------------------------------------------------------\n"); } int min_peri=_max_int_ ; void count_special( int vex ){ if( vexes[vex].n_adj==1 ) return ; memcpy( p_adj_end, vexes[vex].adj, sizeof(t_adj)*vexes[vex].n_adj ); t_vex *p_add = vexes + n_vex ; for( int i=0; i<vexes[vex].n_adj; i++ ){ int to = vexes[vex].adj[i].to ; for( int j=0; j<vexes[to].n_adj; j++ ) if( vexes[to].adj[j].to == vex ) { vexes[to].adj[j].to = n_vex + i ; break ; } p_add->adj = p_adj_end+i , p_add->n_adj=1, p_add++ ; } show_graph( vexes[vex].n_adj ); for( int i=0; i<vexes[vex].n_adj; i++ ){ Bellman_Ford_SPFA( n_vex + i , vexes[vex].n_adj ); for( int j=0; j<vexes[vex].n_adj; j++ ) if( i!=j && sdis[ n_vex+i ] < min_peri ) min_peri = sdis[ n_vex+j ] ; } for( int i=0; i<vexes[vex].n_adj; i++ ){ int to = vexes[vex].adj[i].to ; for( int j=0; j<vexes[to].n_adj; j++ ) if( vexes[to].adj[j].to >= n_vex ) { vexes[to].adj[j].to = vex ; break ; } } show_graph( ); } int main() { freopen("fence6.in", "r", stdin); //freopen("fence6.out","w",stdout); analysis_path( ) ; build_graph( ) ; show_graph(); for( int i=0; i<n_vex; i++ ) count_special(i); cout << min_peri << endl ; return 0; }
附:对偶图上的边搜索环构造算法。
发表评论
-
USACO Training Section 4.2 Cowcycles
2010-01-31 21:11 884英文原题 中文题译 ... -
USACO Training Section 4.2 Job Processing
2010-01-30 17:31 1133英文原题 中文题译 大意: 有N个工件,每个工件要经 ... -
USACO Training Section 4.2 Drainage Ditches ISAP非递归和多路增广递归
2010-01-29 19:39 1849郁闷。不小心覆盖了重 ... -
USACO Training Section 4.2 The Perfect Stall 匈牙利算法的递归和非递归实现
2010-01-28 21:21 1645英文原题 中文题译 ... -
USACO Training Section 4.1 Cryptcowgraphy 奶牛密码
2010-01-27 20:58 1195英文原题 中文题译 大意: 奶牛们要从农场逃跑 ... -
USACO Training Section 4.1 Beef McNuggets
2010-01-26 21:37 968英文原题 中文题译 大意: 给定N个正整数, ... -
USACO Training Section 3.4 Closed Fences
2010-01-23 17:50 1404英文原题 题意 一个 ... -
USACO Training Section 3.4 American Heritage
2010-01-21 23:19 771英文原题 大意:有一个由最多26个大写字母构成的二叉树 ... -
USACO Training Section 3.4 Raucous Rockers
2010-01-21 23:09 798英文原题 大意:有S首歌,要放到D个CD里。每首歌有一个 ... -
USACO Training Section 3.4 Electric Fence
2010-01-21 12:57 971英文原题 大意:给定一个三角形(0,0),(m,n),( ... -
USACO Training Section 3.3 Riding the Fences
2010-01-20 23:38 1206英文原题 中文题译 经典的求欧拉路径:给定最多两个奇 ... -
USACO Training Section 3.3 Shopping Offers
2010-01-19 22:18 916英文原题 中文题译 这是个与日常生活相关的题。商场促销 ... -
USACO Training Section 3.3 A Game
2010-01-19 20:54 1093英文原题 有如下一个双人游戏:N(2 <= N & ... -
USACO Training Section 3.3 Home on the Range
2010-01-19 19:36 772英文原题 中文题译 大意:给定一个01矩阵,计算其中全为 ... -
USACO Training Section 3.3 Camelot
2010-01-19 03:39 1232英文原题 中文题译 ... -
USACO Training Section 3.2 Sweet Butter
2010-01-19 00:10 1046英文原题 中文题译 大意:农场之间有路构成稀疏无向图,若 ... -
USACO Training Section 3.2 Magic Squares
2010-01-18 23:11 930英文原题 中文题译 大意:有人发明了一种有8个块三种变换 ... -
USACO Training Section 3.2 Feed Ratios
2010-01-18 20:52 1307英文原题 中文题译 大意:给出整数a[i][j]和 ... -
USACO Training Section 3.2 Spinning Wheels
2010-01-18 19:37 868英文原题 中文题译 大意:有五个纺车飞轮,每个都有最多五 ... -
USACO Training Section 3.2 Stringsobits
2010-01-18 01:04 990英文原题 中文题译 大意:求至多有L个1的第i个N位二进 ...
相关推荐
ACM----USACO Training(解题博客网),提供了USACO Training解题的代码,可以参考一下
usaco第五章fence3的解题代码,供算法初学者参考
自己写的usaco_training带代码。供参考,有一道题是cheat的。自己看吧。
usaco测试数据+标程 usaco的section1到section5的所有测试数据 以及标准程序
usaco解题报告,就是usaco.training.gateway上面的题目全解
USACO题解+代码+翻译,好东西,超级齐全,对大家帮助不小,特别是现在nocow挂了
usaco section2.3--section5.5源程序。。。。。。。。。。。。。。。。
[USACO 1.1.4]破碎的项链.cpp
USACO全部译题 USACO Training Program Gateway
USACO_培训USACO_培训Ride.java-> Gift1.java->
USACO1-5单元AC的代码~ 1 Chapter1 ...4.1 Section 4.1 4.2 Section 4.2 4.3 Section 4.3 4.4 Section 4.4 5 Chapter5 5.1 Section 5.1 5.2 Section 5.2 5.3 Section 5.3 5.4 Section 5.4 5.5 Section 5.5
USACO training 教程翻译合集(清晰明确)
USACO培训页面美国计算机奥林匹克训练页2015年6月17日开始
One of the answer of the USACO training exercises.
usaco 合集,包括英文原题和中文译题,测试数据以及答案,很全啊!usaco 合集usaco 合集usaco 合集usaco 合集
usaco历年测试数据
usaco 2010-2011 nov news,喜欢usaco的朋友可以看看
USACO题集及答案
某些USACO题目的答案,很详细,代码清晰结构良好,算法高效易于调试
usaco的总结和心得 包括了对题目的分了和总结 以及对题目的解法概括