【CF241E】Flights(差分约束)

【CF241E】Flights(差分约束)

题面

CF
\(n\)个点\(m\)条边,要求给每条边赋一个\(1\)\(2\)的边权,判断能否使得每一条\(1\)\(n\)的路径的权值和都相等,如果可以给出一个方案。

题解

首先有这样一个结论:从\(1\)号点到达任意一个点的所有路径的权值都相同。比较显然,就不证明了。
然后就可以直接差分约束了?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define MAX 1010
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
struct Line{int v,next,w;}e[MAX*10];
int h[MAX],cnt=1;
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
vector<int> E1[MAX],E2[MAX];
int n,m,U[MAX*5],V[MAX*5],vis[MAX],dis[MAX],num[MAX];bool inq[MAX];
queue<int> Q;
void dfs1(int u){vis[u]|=1;for(int v:E1[u])if(!(vis[v]&1))dfs1(v);}
void dfs2(int u){vis[u]|=2;for(int v:E2[u])if(!(vis[v]&2))dfs2(v);}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;++i)
    {
        int u=read(),v=read();U[i]=u;V[i]=v;
        E1[u].push_back(v);E2[v].push_back(u);
    }
    dfs1(1);dfs2(n);
    for(int i=1;i<=m;++i)
        if(vis[U[i]]==3&&vis[V[i]]==3)
        {
            Add(U[i],V[i],1);
            Add(V[i],U[i],-2);
        }
    memset(dis,-63,sizeof(dis));
    Q.push(1);inq[1]=true;dis[1]=0;
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        for(int i=h[u];i;i=e[i].next)
        {
            int v=e[i].v;
            if(dis[v]<dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                if(!inq[v])inq[v]=true,Q.push(v),++num[v];
            }
        }
        if(num[u]>=n){puts("No");return 0;}
        inq[u]=false;
    }
    puts("Yes");
    for(int i=1;i<=m;++i)
        if(vis[U[i]]==3&&vis[V[i]]==3)printf("%d\n",dis[V[i]]-dis[U[i]]);
        else puts("1");
    return 0;
}

转载于:https://www.cnblogs.com/cjyyb/p/11152401.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值