8
20
2015
0

[题解]小K的农场

关键字:差分约束。

Link&Limit


[洛谷1993]  [BZOJ3436]

时间限制:1000ms  空间限制:131072kb

Description


小 K 在 Minecraft 里面建立很多很多的农场,总共 n 个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共 m 个),以下列三种形式描述:

1. 农场 a 比农场 b 至少多种植了 c 个单位的作物。

2. 农场 a 比农场 b 至多多种植了 c 个单位的作物。

3. 农场 a 与农场 b 种植的作物数一样多。

但是,由于小 K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。

Input Format


第一行包括两个整数 n 和 m,分别表示农场数目和小 K 记忆中的信息数目。

接下来 m 行:

如果每行的第一个数是 1,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至少多种植了 c 个单位的作物。

如果每行的第一个数是 2,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至多多种植了 c 个单位的作物。

如果每行的第一个数是 3,接下来有 2 个整数 a,b,表示农场 a 终止的数量和 b 一样多。

Output Format


如果存在某种情况与小 K 的记忆吻合,输出“Yes”,否则输出“No”。

Sample Input #1


3 3

3 1 2

1 1 3 1

2 2 3 2

Sample Output #1


Yes

Hint


对于 100% 的数据保证:1 ≤ n,m,a,b,c ≤ 10000。

差分约束的裸题。如果构造出来的图中有正环(要算最长路)就是No,否则就是Yes。找正环可以用spfa来做,如果一个点入队超过n次则图中含有正环。不过本题的数据范围这样做可能超时,加个限制会好很多。

差分约束的介绍可见:http://tsreaper.is-programmer.com/posts/180182.html

找环也可以用递归版的spfa:http://hzwer.com/3600.html

#include <stdio.h>
#define QLEN 10005
int n,m;
int e[30010][3],p[10010],tot = 0;
int q[10010],dis[10010],cnt[10010],head,tail,ttail = 0;
short vis[10010];
void adde(int sn,int fn,int val)
{
    e[++tot][0] = fn; e[tot][1] = val; e[tot][2] = p[sn]; p[sn] = tot;
}
short spfa()
{
    int i,sn,fn,val;
    for(i=1;i<=n;i++) dis[i] = -999999999;
    head = 1; tail = ttail = 2;
    vis[0] = 1; cnt[0]++;
    while(head!=tail)
    {
        if(ttail>1000000) return 0;
        sn = q[head++];
        for(i=p[sn];i;i=e[i][2])
        {
            fn = e[i][0]; val = e[i][1];
            if(dis[fn]>=dis[sn]+val) continue;
            dis[fn] = dis[sn]+val;
            if(vis[fn]) continue;
            vis[fn] = 1; q[tail++] = fn; cnt[fn]++; ttail++;
            if(cnt[fn]>n) return 0;
            if(tail>QLEN) tail = 1;
        }
        vis[sn] = 0;
        if(head>QLEN) head = 1;
    }
    return 1;
}
int main()
{
    int i,opt,sn,fn,val;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++) adde(0,i,0);
    for(i=1;i<=m;i++)
    {
        scanf("%d",&opt);
        if(opt == 1)
        {
            scanf("%d%d%d",&sn,&fn,&val);
            adde(fn,sn,val);
        }
        else if(opt == 2)
        {
            scanf("%d%d%d",&sn,&fn,&val);
            adde(sn,fn,-val);
        }
        else
        {
            scanf("%d%d",&sn,&fn);
            adde(sn,fn,0); adde(fn,sn,0);
        }
    }
    if(spfa()) printf("Yes");
    else printf("No");
    return 0;
}
Category: 题解 | Tags: 图论 差分约束 洛谷 bzoj | Read Count: 675

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

| Theme: Aeros 2.0 by TheBuckmaker.com