2020hdu多校第三场1009(6797)Tokitsukaze and Rescue

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

题意:有n个点的完全无向图,也就是有n(n-1)/2条无向边,删除k条边之后使得从一号节点到n号节点的最短路径最长,求出次最短路径的最大值

输入:第一行一个整数t,表示样例个数

每个样例第一行两个整数n,k

接下来n(n-1)/2行,每行三个整数u,v,w,表示u,v之间存在一条权值为w的无向边

输出:对于每个样例输出一个整数,表示删除k条边之后的最短路径的最大值

题解:这里面n<=50,k<=min(n-2,5),所以这里直接dfs递归深搜就可以,但比赛的时候没敢尝试,的确非常后悔。先找出一条最短路径,遍历删除路径上的每一条边,然后继续dfs,在删除求出的最短路径上的每一条边,如此直到删除k条边表示一次dfs结束,知道左右可能的情况都遍历之后求出的就是最后的答案

AC代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring> 
using namespace std;
const int N=50+2;
int e[N][N];
int p[N];
int dis[N];
int n,k,sum;
int pre[6][N];
struct node{
    int x,s;
}a,b;
bool operator>(struct node a,struct node b){
    return a.s>b.s;
}
int dij(int x){
    priority_queue<struct node,vector<struct node>,greater<struct node> >q;
    memset(p,0,sizeof(p));
    memset(dis,0,sizeof(dis));
    p[1]=1;
    a.x=1,a.s=0;
    q.push(a);
    while(!q.empty()){
        a=q.top();q.pop();
        p[a.x]=1;
        if(a.x==n) break;
        for(int i=2;i<=n;i++){
            if(p[i]||e[i][a.x]==-1) continue;
            b.x=i,b.s=a.s+e[a.x][i];
            if(dis[i]==0||b.s<dis[i]){
                q.push(b);
                dis[i]=b.s;
                pre[x][i]=a.x;//这里表示删除x条边之后的最短路径中i的前一个结点,
                //第一次写的时候直接使用的一维数组,结果一直WA,最后才发现原来当你下一次深搜之后pre就会被改变,
                //当返回上一层的dfs时继续便利pre就不是原先的pre,就会产生错误 
            }
        }
    }
    while(!q.empty()) q.pop();
    return a.s;
}
void dfs(int x){
    if(x==k){
        if(sum==-1) sum=dij(x);
        else sum=max(sum,dij(x));
        return ;
    }
    dij(x);//当删除x条边之后进行的最短路搜索 
    int now=n,w;//之前写的是now=pre[x][now]然后一直出错,原来要是这么写的话,那么与n节点相连的边就不会被遍历到了 
    while(pre[x][now]!=-1){
        w=e[now][pre[x][now]];
        e[now][pre[x][now]]=-1;
        e[pre[x][now]][now]=-1;//之前没有这一行与下面有注释的那行,然后一直WA,最后才发现自己是真的马虎 
        dfs(x+1);
        e[now][pre[x][now]]=w;
        e[pre[x][now]][now]=w;//与上面标注的那行同时没有写 
        now=pre[x][now];
    }
}
int main(){
    int t;cin>>t;
    while(t--){
        sum=-1;
        memset(pre,-1,sizeof(pre));
        cin>>n>>k;
        int u,v;
        for(int i=1;i<=n*(n-1)/2;i++){
            cin>>u>>v;
            cin>>e[u][v];//使用它邻接矩阵存储图 
            e[v][u]=e[u][v];
        }
        dfs(0);//深搜,0表示当前已经删除0条边 
        cout<<sum<<endl;
    }
    return 0;
}
View Code

写于2020/7/31  14:23


作者:孙建钊
出处:http://www.cnblogs.com/sunjianzhao/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/sunjianzhao/p/13409484.html