zoukankan      html  css  js  c++  java
  • [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 */
  • 相关阅读:
    Windows Mobile 6 sdk installation error, COM3 in use,please check the implementation
    使用lock_sga和pre_page_sga参数保证SGA常驻物理内存 .
    Davinci开发板DM368 nandwrite.c简要分析
    归并排序的实现
    ASP无惧上传类不能上传中文双引号文件及ASP函数InStr存在bug
    cocos2d-x绑定ccb文件
    产品经理的工作感想(3)
    9年经验,总结SEO职业瓶颈
    关于C++中的拷贝构造函数和赋值函数
    实现怎样支持Android重力感应器Sensor编程
  • 原文地址:https://www.cnblogs.com/conver/p/13394597.html
Copyright © 2011-2022 走看看