题目大意:
给N的点,节点间有M条有向边,每条边走过的花费都是1,求取要使从1到N的花费大于K,要去掉的边的最少条数ans
输入:
第一行:N,M,K
接下来是M条边的起点和终点
输出:
Ans
算法分析:
题目中要使达到要求要去掉边的条数最少,要求是1到N的距离要大于K,那么一定要求取1到N之间的最短路,然后再去掉最短路径中的一个点,导致最短路径变长,然后重新求取最短路,做同样的操作,直到最短路径大于K,在这个思路中,我们唯一不确定的就是每次去掉的点的具体标号和一共要去掉点的个数,我们可以枚举深度,逐步加深,去掉的点我们可以枚举最短路径上的点,递归地进行深度优先搜索,查探能不能找到可行解,只要能找到可行解,那么当前深度就是最小深度,因为比它小的深度均找不到解
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <queue> #define MAX 57 using namespace std; bool inqueue[MAX]; bool okay[MAX]; int dis[MAX]; int pre[MAX]; int n,m,k; struct { int v , next; }e[MAX*MAX<<2]; int head[MAX]; int cc; void add ( int u , int v ) { e[cc].next = head[u]; e[cc].v = v; head[u] = cc++; } void spfa ( int u ) { memset ( inqueue , 0 , sizeof ( inqueue) ); memset ( dis , 0x3f , sizeof ( dis ) ); inqueue[u] = true; queue<int> q; dis[u] = 0; q.push ( u ); while ( !q.empty()) { int temp = q.front(); q.pop (); inqueue[u] = false; for ( int i = head[temp] ; i != -1 ; i = e[i].next ) { int v = e[i].v; if ( inqueue[v]||okay[v] ) continue; if ( dis[v] > dis[temp] + 1 ) { dis[v] = dis[temp] + 1; inqueue[v] = true; q.push ( v ); pre[v] = temp; } } } } bool flag = false; int path[MAX][MAX]; void dfs ( int size ) { spfa( 1 ); if ( dis[n] > k ) { flag = true; return; } if ( size == 0 ) return; int cnt = 0; for ( int i = n ; i != 1 ; i = pre[i] ) path[size][cnt++] = i; for ( int i = 1 ; i < cnt ; i++ ) { int index = path[size][i]; if ( okay[index] ) continue; okay[index] = true; dfs ( size - 1 ); okay[index] = false; } } int main ( ) { int u,v; while ( ~scanf ( "%d%d%d" , &n , &m , &k ), n+m+k ) { cc = 0; memset ( head , -1 , sizeof ( head ) ); for ( int i = 0 ; i < m ; i++ ) { scanf ( "%d%d" , &u ,&v ); add ( u , v ); } flag = false; for ( int i = 0 ; i < n ; i++ ) { dfs ( i ); if ( flag ) { printf ( "%d\n" , i ); break; } } } return 0; }