HDU2433 最短路 + 剪枝优化

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2433 ,最短路(SPFA或优化过的Dijstra) + 剪枝优化

  这道题关键还是在几个剪枝上面,没有剪枝会TLE。



先说下几个数组的意义:

  a[]存储M条边的信息;vis[i]表示点i是否访问过;path[i][u][v]表示在点i的所有最短路里,边u - v是否属于某条最短路;cnt[u][v]表示边u - v出现的次数;pos[u][i]表示第i条边在邻接表e[u]中的位置;sum[i]表示预处理时顶点i到所有顶点的最短路的和;dist[i]表示顶点i到其他顶点的最短路的距离;e[i]即邻接表,存储与顶点i邻接的点的信息。

算法:

  先预处理一遍,求得每个顶点的最短路,并存在sum[i]中,如果预处理时发现图不连通,则M次询问都输出"INF";

  处理第i条边的时候,如果这条边出现不止一次,即 cnt[u][v] > 1,这时候除掉这条边后不影响结果,输出预处理的结果即可;

  如果不满足上述条件,就开始求n个顶点的最短路情况:求顶点i的最短路的时候,如果边u - v不在顶点i的最短路中,即 path[i][u][v] == 0时,这时候这条边除掉不影响顶点i的最短路的结果,所以仍为sum[i];如果出现去掉这条边图不连通的情况,这次询问输出"INF"。

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define eps 1e-8
#define INF 1e8
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MOD = 2333333;
const int maxn = 100 + 5;
const int N = 3000 + 5;
struct Edge {
    int v , w;
    bool operator < (const Edge &tmp) const {
        return w > tmp.w;
    }
} a[N];
bool vis[maxn] , path[maxn][maxn][maxn];
int cnt[maxn][maxn] , pos[maxn][N];
int sum[maxn] , dist[maxn];
vector <Edge> e[maxn];

int Dijstra(int s , int n , bool ch)    //Dijstra + 优先队列
{        //ch表示是否为预处理,因为在预处理的时候才需要判断path[i][u][v]的情况
    memset(vis , 0 , sizeof(vis));
    for(int i = 1 ; i <= n ; i++)
        dist[i] = INF;
    dist[s] = 0;
    priority_queue <Edge> que;
    Edge tmp = {s , 0};
    que.push(tmp);
    while(!que.empty()) {
        Edge u = que.top();
        que.pop();
        if(vis[u.v])
            continue;
        vis[u.v] = 1;
        for(int i = 0 ; i < e[u.v].size() ; i++) {
            int j = e[u.v][i].v;
            if(dist[j] > dist[u.v] + e[u.v][i].w) {
                dist[j] = dist[u.v] + e[u.v][i].w;
                if(!vis[j]) {
                    if(ch)    //这条边在最短路中
                        path[s][u.v][j] = path[s][j][u.v] = 1;
                    que.push(e[u.v][i]);
                }
            }
        }
    }
    int ans = 0;
    for(int i = 1 ; i <= n ; i++) {
        if(dist[i] >= INF)
            return INF;
        ans += dist[i];
    }
    return ans;
}
int main()
{
    int n , m , u , v , i , ans;
    while(~scanf("%d %d" , &n , &m))
    {
        memset(path , 0 , sizeof(path));
        memset(cnt , 0 , sizeof(cnt));
        for(i = 1 ; i <= n ; i++)
            e[i].clear();
        for(i = 1 ; i <= m ; i++) {
            scanf("%d %d" , &u , &v);
            Edge tmp = {v , 1};
            e[u].push_back(tmp);
            tmp.v = u;
            e[v].push_back(tmp);
            pos[u][i] = e[u].size() - 1;
            pos[v][i] = e[v].size() - 1;
            cnt[u][v]++;
            cnt[v][u]++;
            a[i].v = u;
            a[i].w = v;
        }
        bool flag = false;
        for(i = 1 , ans = 0 ; i <= n ; i++) {
            sum[i] = Dijstra(i , n , 1);
            if(sum[i] == INF) {
                flag = true;
                break;
            }
            ans += sum[i];
        }
        for(i = 1 ; i <= m ; i++) {
            u = a[i].v;
            v = a[i].w;
            if(flag) {
                puts("INF");
            } else if(cnt[u][v] > 1) {
                printf("%d\n" , ans);
            } else {
                int tmp , res;
                res = ans;
                e[u][pos[u][i]].w = INF;    //删掉第i条边
                e[v][pos[v][i]].w = INF;
                for(int j = 1 ; j <= n ; j++) {
                    if(path[j][u][v]) {
                        tmp = Dijstra(j , n , 0);
                        if(tmp == INF) {
                            puts("INF");
                            break;
                        }
                        res += tmp - sum[j];
                    }
                }
                if(tmp != INF)
                    printf("%d\n" , res);
                e[u][pos[u][i]].w = 1;        //还原这条边
                e[v][pos[v][i]].w = 1;
            }
        }
    }
    return 0;
}
时间: 2024-08-10 17:18:43

HDU2433 最短路 + 剪枝优化的相关文章

poj 1054 The Troublesome Frog (暴力搜索 + 剪枝优化)

题目链接 看到分类里是dp,结果想了半天,也没想出来,搜了一下题解,全是暴力! 不过剪枝很重要,下面我的代码 266ms. 题意: 在一个矩阵方格里面,青蛙在里面跳,但是青蛙每一步都是等长的跳, 从一个边界外,跳到了另一边的边界外,每跳一次对那个点进行标记. 现在给你很多青蛙跳过后的所标记的所有点,那请你从这些点里面找出 一条可能的路径里面出现过的标记点最多. 分析:先排序(目的是方便剪枝,break),然后枚举两个点,这两个 点代表这条路径的起始的两个点.然后是三个剪枝,下面有. 开始遍历时,

HNU 12847 Dwarf Tower(最短路+队列优化)

题目链接:http://acm.hnu.cn/online/?action=problem&type=show&id=12847 解题报告:有n样物品,编号从1到n第i样物品可以通过金币vi买到,同时有m种方法,方法的内容是由两种物品可以构造出另一种物品,现在要你求出得到1物品的价值最小是多少? 当成最短路来解,用邻接表存好m种构造方法,然后用队列里面的点去尝试通过构造的方法使得得到i物品所花的价值更小,如果更新成功,再把更新成功的那个点又加入到队列中. 同时要标记一下这个点是不是正在队列

hdu 4109 dfs+剪枝优化

求最久时间即在无环有向图里求最远路径 dfs+剪枝优化 从0节点(自己增加的)出发,0到1~n个节点之间的距离为1,mt[i]表示从0点到第i个节点目前所得的最长路径 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; const

搜索(剪枝优化):HDU 5113 Black And White

Description In mathematics, the four color theorem, or the four color map theorem, states that, given any separation of a plane into contiguous regions, producing a figure called a map, no more than four colors are required to color the regions of th

Tunnel Warfare(线段树 开方修改+剪枝优化

题意: 给定区间 ,有操作: 0: 对指定区间内元素进行开方 1: 查询指定区间内元素和 一直tle... 因为那个开方操作每次都递归到叶子节点进行了,实际并不需要 增加数学敏感: 开方操作:同指数操作的快速增加一样,开方操作可以使一个数快速减小到1(取整条件下 因此这道题节点的更新可以进行剪枝优化: 若该节点下的所有 叶子节点已经减小到一(这是很快的),则直接return 此外,注意此题的对区间操作的l ,r 并没有说明r>l,因此输入后要判断一下 #include <bits/stdc++

解数独算法的实现——剪枝优化

最近人工智能做个小实验,组队选了个数独游戏,顺便研究了一下.解数独感觉主流思想也就是深搜回溯了吧,优化就是各种剪枝方法. 1 引言 数独起源于18世纪初瑞士数学家欧拉等人研究的拉丁方阵(Latin Square),曾风靡日本和英国.现有解法包括基础解法:摒除法,余数法,进阶解法:区块摒除法(Locked Candidates).数组法(Subset).四角对角线(X-Wing).唯一矩形(Unique Rectangle).全双值坟墓(Bivalue Universal Grave).单数链(X

JZYZOJ1442 [noip2013]华容道 bfs 最短路 剪枝

http://172.20.6.3/Problem_Show.asp?id=1442 想到最短路的简直神了,如果我写我大概只能写一个30分的bfs. 从数据范围可以看出思路是bfs剪枝,但这里的剪枝是通过最短路的预处理实现的. 设需要移动的格子为a格子. 对求最小移动数有意义的移动只有两种,一种是空白格子的移动,一种是a格子移动到空白格子里. 可以得知要把空白格子移动到a格子旁边然后对a格子进行移动. 那么我们有了每次查找时进行的预处理1:求空白格子到a格子四周格子的最短路. 在模拟移动的过程中

[BZOJ1579] [Usaco2009 Feb]Revamping Trails 道路升级(分层图最短路 + 堆优化dijk)

传送门 dis[i][j]表示第i个点,更新了j次的最短路 此题不良心,卡spfa #include <queue> #include <cstdio> #include <cstring> #include <iostream> #define N 50001 using namespace std; struct node { int a, b, c; node(int a, int b, int c) : a(a), b(b), c(c) {} boo

HDU 5828 Rikka with Sequence (线段树+剪枝优化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5828 给你n个数,三种操作.操作1是将l到r之间的数都加上x:操作2是将l到r之间的数都开方:操作3是求出l到r之间的和. 操作1和3就不说了,关键是开方操作. 一个一个开方,复杂度太高,无疑会T.所以我们来剪枝一下. 我们可以观察,这里一个数最多开方4,5次(loglogx次)就会到1,所以要是一段区间最大值为1的话,就不需要递归开方下去了.这是一个剪枝. 如果一段区间的数都是一样大小(最大值等于