Bayan 2012-2013 Elimination Round (ACM ICPC Rules, English statements) E. Flights

19 篇文章 0 订阅

题意

给你一个DAG
然后边权可以是0也可以是1
问你是否存在方案,使得1到n的每一条路径长度都一样

题解

f[i] f [ i ] i i n的最短路
如果有一条边 i,j i , j
那么显然有 1<=f[i]f[j]<=2 1 <= f [ i ] − f [ j ] <= 2
差分约束一下就可以了
要注意的是,要处理的点必须满足有一条1~n的路径包含他

CODE:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=5005;
int n,m;
struct qq
{
    int x,y,z,last;
}e[N*2];int num,last[N];
qq E[N*2];int Last[N];
void init (int x,int y,int z)
{
    num++;
    e[num].x=x;e[num].y=y;e[num].z=z;
    e[num].last=last[x];
    last[x]=num;
}
int cnt[N];
int f[N];
int X[N],Y[N];
bool in[N];
bool ok[N];
bool o[N];
bool bfs ()
{
    memset(f,127,sizeof(f));
    queue<int> q;
    q.push(n);f[n]=0;
    while (!q.empty())
    {
        int x=q.front();q.pop();in[x]=false;
        for (int u=last[x];u!=-1;u=e[u].last)
        {
            int y=e[u].y;
            if (ok[y]==false) continue;
            if (f[y]>f[x]+e[u].z)
            {
                f[y]=f[x]+e[u].z;
                cnt[y]++;
                if (cnt[y]>n) return false;
                if (in[y]==false)
                {
                    in[y]=true;
                    q.push(y);
                }
            }
        }
    }
    return true;
}
void Init (int x,int y)
{
    num++;
    E[num].x=x;E[num].y=y;
    E[num].last=Last[x];
    Last[x]=num;
}

void bfs1 (int x)
{
    memset(o,false,sizeof(o));
    queue<int> q;q.push(x);o[x]=true;
    while (!q.empty())
    {
        int xx=q.front();q.pop();
        if (x==1&&xx==n) continue;
        if (x==n&&xx==1) continue;
        for (int u=Last[xx];u!=-1;u=E[u].last)
        {
            int y=E[u].y;
            if (o[y]) continue;
            o[y]=true;
            q.push(y);
        }
    }
}
int main()
{
    num=0;memset(last,-1,sizeof(last));
    scanf("%d%d",&n,&m);
    for (int u=1;u<=m;u++)
    {
        scanf("%d%d",&X[u],&Y[u]);
        init(Y[u],X[u],2);init(X[u],Y[u],-1);
    }
    num=0;memset(Last,-1,sizeof(Last));
    for (int u=1;u<=m;u++)  Init(X[u],Y[u]);
    bfs1(1);
    for (int u=1;u<=n;u++) ok[u]=o[u];

    num=0;memset(Last,-1,sizeof(Last));
    for (int u=1;u<=m;u++)  Init(Y[u],X[u]);
    bfs1(n);
    for (int u=1;u<=n;u++) ok[u]&=o[u];

    if (bfs()==false)   {printf("No\n");return 0;}
    printf("Yes\n");
    for (int u=1;u<=m;u++)  
    {
        if (ok[X[u]]&ok[Y[u]])  printf("%d\n",f[X[u]]-f[Y[u]]);
        else printf("1\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值