zoukankan      html  css  js  c++  java
  • (好题)2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest F Pizza Delivery

    题意:给n个点m条边的有向图。每次使一条边反向,问你1到2的最短路变短,变长,还是不变。

    解法:遇到这种题容易想到正向求一遍最短路d1,反向再求一遍最短路d2。纪录原图上的最短路为ans,然后分开考虑各种情况。

    变短的情况:d1[y[i]]+d2[x[i]]+z[i]<ans  

    否则就剩下不变和变长两种情况:那么如果边(x,y)是起点到终点的最短路必须边的话,就会变长,否则会不变。

    接下来的问题是  怎么求最短路的必经边?

    求出原图1到2最短路图(这里要和求单源点的最短路图区别开来,单源点的最短路图使起点到所有其他点的最短路的集合),求法:如果d1[x[i]]+z[i]+d2[y[i]]==ans的话边(x[i],y[i])就在起点到终点的最短路图上。  把这个图变为无向图,用tarjan求桥。如果边(x,y)是桥的话就是必经边,否则为非必经边。

    细节详见代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,LL> pii;
    const int N=1e5+10;
    LL n,m,ans;
    LL d1[N],d2[N],x[N],y[N],z[N];
    
    LL cnt=1,head[N],to[N<<1],nxt[N<<1],len[N<<1];
    void add_edge(LL x,LL y,LL z) {
        nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt;
    }
    
    bool vis[N]; 
    priority_queue<pii> q;
    void Dijkstra(LL d[],LL s) {
        while (!q.empty()) q.pop();
        memset(vis,0,sizeof(vis));
        d[s]=0; q.push(make_pair(0,s));
        while (!q.empty()) {
            pii x=q.top(); q.pop();
            if (vis[x.second]) continue;
            vis[x.second]=1;
            for (LL i=head[x.second];i;i=nxt[i]) {
                LL y=to[i];
                if (d[y]>d[x.second]+len[i]) {
                    d[y]=d[x.second]+len[i];
                    q.push(make_pair(-d[y],y));
                }
            }
        }
    }
    
    int num,low[N],dfn[N],bridge[N];
    void tarjan(int x,int in) {
        dfn[x]=low[x]=++num;
        for (int i=head[x];i;i=nxt[i]) {
            int y=to[i];
            if (!dfn[y]) {
                tarjan(y,i);
                low[x]=min(low[x],low[y]);
                
                if (low[y]>dfn[x])
                    bridge[len[i]]=bridge[len[i^1]]=1;
            } else if (i!=(in^1))
                low[x]=min(low[x],dfn[y]);
        }
    }
    
    void getbridge() {
        cnt=1; memset(head,0,sizeof(head));
        for (int i=1;i<=m;i++)
            if (d1[x[i]]+z[i]+d2[y[i]]==ans) 
                add_edge(x[i],y[i],i),add_edge(y[i],x[i],i);
        for (int i=1;i<=n;i++)
            if (!dfn[i]) tarjan(i,0);    
    }
    
    int main()
    {
        cin>>n>>m;
        for (int i=1;i<=m;i++) scanf("%lld%lld%lld",&x[i],&y[i],&z[i]);
        
        memset(d1,0x3f,sizeof(d1)); memset(d2,0x3f,sizeof(d2));
        for (int i=1;i<=m;i++) add_edge(x[i],y[i],z[i]);
        Dijkstra(d1,1);
        
        cnt=1; memset(head,0,sizeof(head));
        for (int i=1;i<=m;i++) add_edge(y[i],x[i],z[i]);
        Dijkstra(d2,2);
        
        ans=d1[2]; getbridge();
        
        for (int i=1;i<=m;i++)
            if (ans>d1[y[i]]+d2[x[i]]+z[i]) puts("HAPPY");
            else if (bridge[i]) puts("SAD"); else puts("SOSO");
        return 0;
    } 
  • 相关阅读:
    快速创建ssm项目
    String 的基础知识点梳理一
    消息中间件ActiveMQ
    log4j.properties
    数据库基础
    pycharm快捷键
    HTML其他标签
    HTML基本标签
    概率论基础2
    概率论基础1
  • 原文地址:https://www.cnblogs.com/clno1/p/10846506.html
Copyright © 2011-2022 走看看