UVALive 4080 Warfare And Logistics(最短路树)

来源:互联网 发布:5.1声道测试软件 编辑:程序博客网 时间:2024/05/18 13:46

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2081

题目大意:给你n个点m条双向边的图。d(i,j)表示以 i 为源点时,j 到i的最短路。让你算 c = d(1,1)+d(1,2)+..+.d(1,n)+d(2,1)+d(2,2)+...+d(2,n)+......+d(n,n),如果d(i,j)不连通, + 的时候就用输入的 l 代替,。然后你可以删掉一条边,使得上面那个 c 最大,并求出这个最大值。

解题思路:第一个问题很好解决,floyd 和 n 次 dij 或者 spfa 都可以。关键是删掉一条边那里。如果枚举删掉的边,那复杂度就是 m*n^3 ,换 dij 和 spfa 应该也差不多,都过不了。此时就要想到,不是无论删除哪条边,所有东西都要重新算的,只有那些在最短路树上的边被删除时,才需要重新算。所以就是先 dij 处理出 n 个最短路树和每个为源点时的最短路和。然后就是上面的步骤了,先判断要不要重新算就好了。这里有个陷阱的,就是有重边。如果你要删除了两个点之间的一条边,那么肯定是删的最短的那一条,因为要使 c 最大么,删掉后不是就没有边了,应该是第二短的边顶上,所以这里还要稍微处理一下。

其实我不会算上面这个算法的复杂度,求哪位好心的大神指点~~~

代码如下:

#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<algorithm>using namespace std;typedef long long lld;const int INF = 0x0fffffff;const int MAXN = 111;vector<int> G[MAXN][MAXN];bool flag[MAXN][MAXN][2];void init(int n){    for(int i = 1;i <= n;i++)        for(int j = 1;j <= n;j++)            G[i][j].clear();}void add_edge(int s,int t,int val){    G[s][t].push_back(val);    if(G[s][t].size() <= 2) flag[s][t][G[s][t].size()-1] = 1;}struct  Node{    int id;    int val;    Node(int iid,int vval)    {        id = iid;        val = vval;    }    bool operator < (const Node& tmp) const    {        return val > tmp.val;    }};priority_queue<Node> q;bool done[MAXN];int d[MAXN];int p[MAXN][MAXN];int first;void dij(int s,int n){    for(int i = 1;i <= n;i++)        d[i] = INF;    d[s] = 0;    p[s][s] = -1;    q.push(Node(s,0));    memset(done,0,sizeof(done));    while(!q.empty())    {        Node cur = q.top();        q.pop();        if(done[cur.id]) continue;        done[cur.id] = 1;        for(int i = 1;i <= n;i++)            for(int j = 0;j < G[cur.id][i].size();j++)            {                if(flag[cur.id][i][j])                {                    int tmp = cur.val+G[cur.id][i][j];                    if(tmp < d[i])                    {                        d[i] = tmp;                        if(first) p[s][i] = cur.id;                        q.push(Node(i,tmp));                    }                    break;                }            }    }}lld cc[MAXN];int main(){    int n,m,l;    while(~scanf("%d%d%d",&n,&m,&l))    {        init(n);        while(m--)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            add_edge(a,b,c);            add_edge(b,a,c);        }        for(int i = 1;i <= n;i++)            for(int j = 1;j <= n;j++)                sort(G[i][j].begin(),G[i][j].end());        lld c = 0;        first = 1;        for(int i = 1;i <= n;i++)        {            dij(i,n);            cc[i] = 0;            for(int j = 1;j <= n;j++)            {                if(d[j] >= INF) cc[i] += l;                else cc[i] += d[j];            }            c += cc[i];        }        first = 0;        printf("%lld ",c);        lld ans = 0;        for(int i = 1;i <= n;i++)        {            for(int j = i+1;j <= n;j++)                if(G[i][j].size())                {                    flag[i][j][0] = flag[j][i][0] = 0;                    lld tmp = 0;                    for(int s = 1;s <= n;s++)                        if(p[s][i] == j || p[s][j] == i)                        {                            dij(s,n);                            for(int k = 1;k <= n;k++)                                if(d[k] >= INF) tmp += l;                                else tmp += d[k];                        }                        else tmp += cc[s];                    flag[i][j][0] = flag[j][i][0] = 1;                    ans = max(ans,tmp);                }        }        printf("%lld\n",ans);    }    return 0;}


0 0