[CF241E]Flights

[CF241E]Flights

题目大意:

给一张\(n(n\le1000)\)个点\(m(m\le5000)\)条边的DAG,确定每条边的边权\(w_i(w_i\in\{1,2\})\),使得所有从\(1\)\(n\)的路径拥有相同的长度。

思路:

首先用BFS求出所有与\(1\)\(n\)路径有关的点构成的子图。

这样,\(1\)到子图上每个点的长度都是确定的,即终点相同的路径拥有相同的长度。有\(d_i\)表示点\(1\)到点\(i\)的距离,则对于边\(u\to v\),有\(1\le d_v-d_u\le2\)。这样我们就可以得到一个差分约束系统,使用SPFA求最长路即可。

源代码:

#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
const int N=1001,M=5000;
struct Edge {
    int u,v;
};
Edge edge[M];
std::vector<int> e[N];
std::vector<Edge> h[N];
int n,m,vis[N],dis[N];
bool f[N],g[N],inq[N];
std::queue<int> q;
inline void bfs1() {
    for(register int i=0;i<m;i++) {
        e[edge[i].u].push_back(edge[i].v);
    }
    q.push(1);
    f[1]=true;
    while(!q.empty()) {
        const int &x=q.front();
        for(auto &y:e[x]) {
            if(!f[y]) {
                q.push(y);
                f[y]=true;
            }
        }
        q.pop();
    }
    for(register int i=1;i<=n;i++) {
        e[i].clear();
    }
}
inline void bfs2() {
    for(register int i=0;i<m;i++) {
        e[edge[i].v].push_back(edge[i].u);
    }
    q.push(n);
    g[n]=true;
    while(!q.empty()) {
        const int &x=q.front();
        for(auto &y:e[x]) {
            if(!g[y]) {
                q.push(y);
                g[y]=true;
            }
        }
        q.pop();
    }
    for(register int i=1;i<=n;i++) {
        e[i].clear();
    }
}
inline void spfa() {
    q.push(1);
    while(!q.empty()) {
        const int &x=q.front();
        for(auto &j:h[x]) {
            const int &y=j.u,&w=j.v;
            if(dis[x]+w>dis[y]) {
                dis[y]=dis[x]+w;
                if(!inq[y]) {
                    inq[y]=true;
                    q.push(y);
                    if(++vis[y]>n) {
                        throw 0;
                    }
                }
            }
        }
        q.pop();
        inq[x]=false;
    }
}
int main() {
    n=getint(),m=getint();
    for(register int i=0;i<m;i++) {
        const int u=getint(),v=getint();
        edge[i]=(Edge){u,v};
    }
    bfs1();
    bfs2();
    for(register int i=0;i<m;i++) {
        const int &u=edge[i].u,&v=edge[i].v;
        if(f[u]&&g[u]&&f[v]&&g[v]) {
            h[u].push_back((Edge){v,1});
            h[v].push_back((Edge){u,-2});
        }
    }
    try {
        spfa();
    } catch(...) {
        puts("No");
        return 0;
    }
    puts("Yes");
    for(register int i=0;i<m;i++) {
        const int &u=edge[i].u,&v=edge[i].v;
        if(f[u]&&g[u]&&f[v]&&g[v]) {
            printf("%d\n",dis[v]-dis[u]);
        } else {
            puts("1");
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/skylee03/p/9718275.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值