[hdu-6797]Tokitsukaze and Rescue 爆搜枚举+dijstra最短路 2020多校3

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6797

题目大意:n个点的完全图,要求删k条边,求删完k条边后的最短路的最大值。

3n50,1kmin(n2,5)   边权为[ 1 ,  10^4 ] 的随机数

题解:

删的边一定在当前的最短路上,跑一遍dijstra,暴力枚举删最短路上的哪条边,然后进行下一轮删边,变成删除k-1条边的子问题。

在删完k条边时,跑一遍用当前的dis[n]更新ans。

ps:1. 记录边的时候开一个pre记录每个点前面的结点,然后能顺着找到路径。

2.因为有好几轮记录,但是是按深度dfs的,最多有k层,要把pre开成二维数组,最多 pre[k][n]就可以了。 【一开始没想到是按深度的,把每轮dijstra的pre都记录了,pre开的非常大,有pre[1000000][50],也没炸】

 正确性:

因为题目中一句重要的:

 在边权随机的情况下,最短路的边条数很小。【官方的吐槽:一条路A  一条路B A的边数比B多,要使A的长度<B的长度,在每条边值域相同的情况下概率很小的】

时间复杂度  (n^2   * e^k)e是最短路的边数。

当时没想到,要不早就爆搜了!!qwq

官方标程【觉得写得非常的简洁,先放出来】:

1.pre不用开大

2.稠密图直接写n^2的dijstra,不用堆优化

 1 #include<cstdio>
 2 const int N=55,K=15,inf=100000000;
 3 int Case,n,m,i,j,x,y,z,g[N][N],d[N],f[K][N],v[N],ans;
 4 void dfs(int m){
 5   int i,j,k;
 6   for(i=1;i<=n;i++)d[i]=inf,f[m][i]=v[i]=0;
 7   for(d[1]=0,i=1;i<=n;i++){
 8     k=0;
 9     for(j=1;j<=n;j++)if(!v[j])if(!k||d[j]<d[k])k=j;
10     v[k]=1;
11     for(j=1;j<=n;j++)if(!v[j]&&d[k]+g[k][j]<d[j]){
12       d[j]=d[k]+g[k][j];
13       f[m][j]=k;
14     }
15   }
16   if(!m){
17     if(ans<d[n])ans=d[n];
18     return;
19   }
20   for(i=n;i!=1;i=j){
21     j=f[m][i];
22     k=g[i][j];
23     g[i][j]=g[j][i]=inf;
24     dfs(m-1);
25     g[i][j]=g[j][i]=k;
26   }
27 }
28 int main(){
29   scanf("%d",&Case);
30   while(Case--){
31     scanf("%d%d",&n,&m);
32     for(i=1;i<=n;i++)for(j=1;j<=n;j++)g[i][j]=i==j?0:inf;
33     for(i=1;i<=n*(n-1)/2;i++){
34       scanf("%d%d%d",&x,&y,&z);
35       g[x][y]=g[y][x]=z;
36     }
37     ans=0;
38     dfs(m);
39     printf("%d
",ans);
40   }
41 }

2.个人ac代码

弊端:

1.pre数组开的太大

2.堆优化dijstra比较冗余

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int INF = 0x3f3f3f3f;
  5 const int MAXN = 55,mu=1000000;
  6 const int MAXM = 3025;
  7 int pre[mu][MAXN],mp[MAXN][MAXN],t[MAXM],d[MAXN],tot;
  8 
  9 inline int read() {
 10     int x = 0, ff = 1; char ch = getchar();
 11     while(!isdigit(ch)) {
 12         if(ch == '-') ff = -1;
 13         ch = getchar();
 14     }
 15     while(isdigit(ch)) {
 16         x = (x << 1) + (x << 3) + (ch ^ 48);
 17         ch = getchar();
 18     }
 19     return x * ff;
 20 }
 21 int n, m, k;
 22 struct love
 23 {
 24     int num, d;
 25 };
 26 
 27 bool operator < (love a, love b)
 28 {
 29     return a.d > b.d;
 30 }
 31 /*used  是否使用过结点
 32 d 到结点1的距离
 33 */
 34 priority_queue <love> q;
 35 bool used[MAXN];
 36 void dijkstra()
 37 {
 38     memset(used,0,sizeof(used));
 39     for(int i=0;i<=n;i++)d[i]=INF;
 40     int s=1;
 41     q.push((love){s, 0});
 42     d[s] = 0;
 43     used[s] = 1;
 44     while (!q.empty())
 45     {
 46         int now = q.top().num;
 47         q.pop();
 48         used[now] = 1;
 49         for (int i = 1; i <=n; i ++)
 50         {
 51             if (d[i] > d[now] + mp[now][i])
 52             {
 53                 d[i] = d[now] + mp[now][i];
 54                 pre[tot][i]=now;
 55                 if (!used[i])
 56                 {
 57                     q.push((love){i, d[i]});
 58                 }
 59             }
 60         }
 61     }
 62 }
 63 int totans;
 64 
 65 void dfs(int cnt){
 66     tot++;
 67     int num=tot;
 68     dijkstra();
 69     if(cnt==k+1){
 70         totans=max(totans,d[n]);
 71         return;
 72     }
 73     int uu=n;
 74     while(uu!=1){
 75         //暴力枚举删最短路上的哪条边
 76        // printf("uu: %d  pre[uu]: %d 
",uu,pre[uu]);
 77         int gg=pre[num][uu];
 78         int tmp=mp[uu][gg];
 79         mp[uu][gg]=INF;
 80         mp[gg][uu]=INF;
 81         dfs(cnt+1);//搜完之后要回溯
 82         mp[uu][gg]=tmp;
 83         mp[gg][uu]=tmp;
 84         uu=gg;
 85         //cout<<"haha"<<uu<<endl;
 86     }
 87 }
 88 int main(){
 89     int tt;
 90     scanf("%d",&tt);
 91     while(tt--){
 92      //   cout<<INF<<endl;
 93         n=read();
 94         k=read();
 95         m=(n-1)*n/2;
 96         totans=0;
 97         for(int i = 1; i <= m; ++i) {
 98             int x,y,v;
 99             x = read(); y = read(); v = read();
100             mp[x][y]=mp[y][x]=v;
101         }
102         dfs(1);
103         printf("%d
",totans);
104     }
105     return 0;
106 }
107 /*
108 10
109 5 10 5
110 1 2 2990
111 1 3 2414
112 1 4 4018
113 1 5 6216
114 2 3 9140
115 2 4 4169
116 2 5 550
117 3 4 6618
118 3 5 3206
119 4 5 105
120 
121 */
原文地址:https://www.cnblogs.com/conver/p/13394597.html