POJ 3921 Destroying the bus stations

来源:互联网 发布:知乎 王家卫 章子怡 编辑:程序博客网 时间:2024/04/29 19:41

题目大意:

        一个有向图有n个顶点(0 < n ≤ 50,编号为1 - n),m条边(0 < m ≤ 4,000),两个顶点之间可以有多条边,现要求删除最少的点使得从1号到n号顶点不存在长度≤k的路径(0 < k < 1,000),但是不能直接删掉1号和n号点。

        现有多个测例,每个测例中都给出n、m、k,对于m条边都给出每条边的起始点序号和终止点序号,测例以n、m、k都等于0结束,对于每个测例都要求输出最少删除的点数。

题目链接

注释代码:

/*                                                * Problem ID : POJ 3921 Destroying the bus stations * Author     : Lirx.t.Una                                                * Language   : C++                               * Run Time   : 110 ms                                                * Run Memory : 152 KB                                               */ #include <memory.h>#include <stdio.h>#defineTRUE1#defineFALSE0//maximum number of bus stations//公交站的最大数量#defineMAXSTAN51//maximum number of roads//公交站之间通路的最大数量#defineMAXRODN4001typedefcharBOOL;//图的邻接表shorthd[MAXSTAN];//headshortac[MAXRODN];//arcshortnx[MAXRODN];//nextshorte;//edge//BFS广搜出一条从1到n的最短路径//由于每条边长都是1//所以没有必要Dij或者SPFA//广搜到的第一条通路即为1到n的最短路径charq[MAXSTAN];//queueBOOLvist[MAXSTAN];//visitedBOOLdl[MAXSTAN];//deleted,dl[i]用于判断i点是否被删除charovl[MAXSTAN];//overlap,表示i点的重叠层数,用于剪枝charprv[MAXSTAN][MAXSTAN];//用于记录BFS搜索出的最短路径//prv[depth][i]表示在第depth层中BFS搜出的路径中i点的前驱结点编号charbotm;//迭代深搜的界限bottomintn, m, k;voidaddarc( int u, int v ) {nx[e] = hd[u];ac[e] = v;hd[u] = e++;}intlen(char *prv) {//计算找出的路径的长度intu;//临时变量,指向一个点intcnt;//计数变量,记录路径长度cnt = 0;u   = n;while ( u != 1 ) {u = prv[u];cnt++;}return cnt;}BOOLbfs(char *prv) {//寻找一条最短路径intfront, tail;intu, v;inti;memset(vist, 0, sizeof(vist));vist[1] = TRUE;q[0]  = 1;front = 0;tail  = 1;while ( front < tail ) {u = q[front++];for ( i = hd[u]; i; i = nx[i] )if ( !vist[ v = ac[i] ] && !dl[v] ) {//注意!!//还要看一下该店是否在dfs中删除了!!!prv[v] = u;if ( v == n )goto s;vist[v]   = TRUE;q[tail++] = v;}}return TRUE;//表示1到n不可达,即1到n的距离无穷大,因此一定大于k,所以成功退出s:if ( len(prv) > k )//如果最短路径存在,计算其长度是否满足题中大于k的要求return TRUE;return FALSE;}BOOLdfs(int dp) {//迭代深搜,DFSID//depth,表示迭代的深度//这里就表示当前要删掉第几个点(第dp个点)if ( dp > botm )//超出界限则失败退出return FALSE;if ( bfs( prv[dp] ) )//如果在当前深度中存在>k的最短路径则成功退出return TRUE;intu;//临时变量,指向点的指针for ( u = prv[dp][n]; u != 1; u = prv[dp][u] ) {//遍历枚举当前层次中//最短路径中的每个点//枚举的顺序是从n到1if ( !ovl[u] ) {//!!!重要的剪枝//如果u在上面几层中被试探过了//就不必删除,可以直接忽略//即如果有原图中有部分路径相互重叠,如果上层搜索过重叠部分,则下层可以不必检验//可以使算法大大加速//具体证明不详!dl[u] = TRUE;//先删掉if ( dfs( dp + 1 ) )//然后在下一层中找一条最短路径检验是否合格return TRUE;dl[u] = FALSE;//检验完后再枚举上一个点,将u点还原!}ovl[u]++;//将u的重叠值+1}for ( u = prv[dp][n]; u != 1; u = prv[dp][u] )ovl[u]--;//当一层搜索完了就将所有重叠值-1,表示退出这1层,回溯到上层//使上层的ovl值保持为原样return FALSE;//没有搜出想要的结果,因此失败退出回溯到上层}intmain() {intu, v;while ( scanf("%d%d%d", &n, &m, &k), n ) {memset(hd, 0, sizeof(hd));e = 1;while ( m-- ) {scanf("%d%d", &u, &v);addarc( u, v );}for ( botm = 0; botm <= n - 2; botm++ ) {//表示先删0个点,再试一试只删1个点,再试只删2个点...//1和n不能删//第一次碰到的可行的结果就是最终答案//将删点信息和重叠信息初始化(清空)memset(dl, 0, sizeof(dl));memset(ovl, 0, sizeof(ovl));if ( dfs(0) ) {//从0个点删到botm个点为止printf("%d\n", botm);break;}}}return 0;}

无注释代码:

#include <memory.h>#include <stdio.h>#defineTRUE1#defineFALSE0#defineMAXSTAN51#defineMAXRODN4001typedefcharBOOL;shorthd[MAXSTAN];shortac[MAXRODN];shortnx[MAXRODN];shorte;charq[MAXSTAN];BOOLvist[MAXSTAN];BOOLdl[MAXSTAN];charovl[MAXSTAN];charprv[MAXSTAN][MAXSTAN];charbotm;intn, m, k;voidaddarc( int u, int v ) {nx[e] = hd[u];ac[e] = v;hd[u] = e++;}intlen(char *prv) {intu;intcnt;cnt = 0;u   = n;while ( u != 1 ) {u = prv[u];cnt++;}return cnt;}BOOLbfs(char *prv) {intfront, tail;intu, v;inti;memset(vist, 0, sizeof(vist));vist[1] = TRUE;q[0]  = 1;front = 0;tail  = 1;while ( front < tail ) {u = q[front++];for ( i = hd[u]; i; i = nx[i] )if ( !vist[ v = ac[i] ] && !dl[v] ) {prv[v] = u;if ( v == n )goto s;vist[v]   = TRUE;q[tail++] = v;}}return TRUE;s:if ( len(prv) > k )return TRUE;return FALSE;}BOOLdfs(int dp) {if ( dp > botm )return FALSE;if ( bfs( prv[dp] ) )return TRUE;intu;for ( u = prv[dp][n]; u != 1; u = prv[dp][u] ) {if ( !ovl[u] ) {dl[u] = TRUE;if ( dfs( dp + 1 ) )return TRUE;dl[u] = FALSE;}ovl[u]++;}for ( u = prv[dp][n]; u != 1; u = prv[dp][u] )ovl[u]--;return FALSE;}intmain() {intu, v;while ( scanf("%d%d%d", &n, &m, &k), n ) {memset(hd, 0, sizeof(hd));e = 1;while ( m-- ) {scanf("%d%d", &u, &v);addarc( u, v );}for ( botm = 0; botm <= n - 2; botm++ ) {memset(dl, 0, sizeof(dl));memset(ovl, 0, sizeof(ovl));if ( dfs(0) ) {printf("%d\n", botm);break;}}}return 0;}

单词解释:

barrack:n, 营房,兵营

military:adj, 军事的,军用的

vehicle:n, 车辆

ban:vt, 禁止

mission:n, 使命,任务

spy:n, 间谍

0 0
原创粉丝点击