HDU多校3 - 6797 Tokitsukaze and Rescue(dfs+最短路)

题目链接:点击查看

题目大意:给出一张无向完全图,现在要求删除 k 条边,问删除后的最短路的最大值是多少,k 最大是 5

题目分析:很玄学的一道题,数据范围非常小且时间给了 8 秒,比赛时我直接暴力贪心,每次 tarjan 直接找最短路的必经边然后删除,但过了样例却返回了 WA ,然后就自闭了,看了题解之后真的感觉非常奇妙

读完题后就注意到题目中说了所有的边权均是随机数,题解说因为随机数的期望都是一样的,最短路求出后每次只有一条,且涉及到的边数非常少,其他的反例的几率非常非常小,这样可以对每一层进行爆搜,时间复杂度为 c^k * n^2,c 为最短路的边数

然后实现就好了,注意要用朴素的 n * n 的迪杰斯特拉而不是堆优化的,因为堆优化的时间复杂度为 ( n + m ) * logm ,在这个题中显然不如 n * n 的要表现优秀

至于找最短路上的边,我是参考了 std 记录每个点的前驱来实现的,换句话说每次最短路有且仅有一条(不会证明),当然也可以正反各求一次最短路,然后 n * n 去枚举每条边判断是否位于最短路上,不知道会不会超时

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
  
typedef long long LL;
  
typedef unsigned long long ull;
  
const int inf=0x3f3f3f3f;

const int N=55;

int maze[N][N],pre[6][N],d[N],ans,n;

bool vis[N];

void Dijkstra(int k)
{
	memset(d,inf,sizeof(int)*(n+5));
	memset(vis,false,n+5);
	d[1]=0;
	for(int i=1;id[u]+maze[u][v])
			{
				d[v]=d[u]+maze[u][v];
				pre[k][v]=u;
			}
	}
}

void dfs(int k)
{
	Dijkstra(k);
	if(!k)
	{
		ans=max(ans,d[n]);
		return;
	}
	int pos=n;
	while(pos!=1)
	{
		int u=pos,v=pre[k][pos];
		int temp=maze[u][v];
		maze[u][v]=maze[v][u]=inf;
		dfs(k-1);
		maze[u][v]=maze[v][u]=temp;
		pos=pre[k][pos];
	}
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int w;
	cin>>w;
	while(w--)
	{
		int k;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n*(n-1)/2;i++)
		{
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			maze[u][v]=maze[v][u]=w;
		}
		ans=0;
		dfs(k);
		printf("%d\n",ans);
	}




















    return 0;
}

 

你可能感兴趣的:(最短路,dfs)