【BZOJ2330】【tyvj1785】【codevs2404】糖果,第一次的差分约束

传送门1
传送门2
传送门3
写在前面:tyvj打卡的不归路and第一次写差分约束,比较生疏……
思路:
1.看到题目给出了元素之间的大小关系,我们比较容易想到了差分约束,而且求的是最少糖果数,所以可以转换成各点到源点最长路径的和(我这里蛋疼了好久,一开始用的是最短路径+奇奇怪怪的方法,只过了70)
2.接下来就是建图了
点与点
①x=y就是不等式组{x-y>=0,y-x>=0},所以我们在x,y中互相连两条长度为0的边即可
②x<y可以转化成y-x>=1,所以连一条x到y的长度为1的边
③x>=y可以转化成x-y>=0,所以连一条y到x的长度为0的边
④x>y可以转化成x-y>=1,所以连一条y到x的长度为1的边
⑤y>=x可以转化成y-x>=0,所以连一条x到y的长度为0的边
关于源点
由于每个人都要分到糖(即最长距离大于0),所以从源点向所有点连一条距离为1的边
3.建图完毕即可跑SPFA求最长路径,与求最短路径类似,只不过dis值不用改,0就行
注意:
1.从源点向外连边时从n到1反着建,不然会莫名T一组
2.操作2,4时判断x,y是否相等,相等即无解,理由同上
3.SPFA中开一个num数组记录每个点进入队列的次数,>=n即是存在负环(别想着用什么√n优化),退出

推荐两篇不错的差分约束入门文章:
http://www.cnblogs.com/void/archive/2011/08/26/2153928.html
http://blog.csdn.net/xuezhongfenfei/article/details/8685313

#include<bits/stdc++.h>
#define LL long long
using namespace std;
int tot,n,m,opr,x,y,start;
int first[100010],num[100010];
LL dis[100010],ans,minn;
bool flag[100010];
queue<int> q;
struct os
{
    int fa,son,next,v;
}a[500010];
int in()
{
    int f=1,t=0;
    char ch=getchar();
    while (ch>'9'||ch<'0')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9') t=t*10+ch-'0',ch=getchar();
    return f*t;
}
void add(int x,int y,int z)
{
    a[++tot].fa=x;
    a[tot].son=y;
    a[tot].v=z;
    a[tot].next=first[x];
    first[x]=tot;
}
main()
{
    n=in();
    m=in();
    for (int i=1;i<=m;i++)
    {
        opr=in();
        x=in();
        y=in();
        if (opr==1)
        add(x,y,0),
        add(y,x,0);
        else if (opr==2)
        {
            if (x==y) printf("-1"),exit(0);
            add(x,y,1);
        }
        else if (opr==3)
        add(y,x,0);
        else if (opr==4)
        {
            if (x==y) printf("-1"),exit(0);
            add(y,x,1);
        }
        else
        add(x,y,0);
    }
    start=n+1;
    for (int i=n;i>=1;i--) add(start,i,1);
    num[start]=flag[start]=1;
    q.push(start);
    while (!q.empty())
    {
        int k=q.front();
        flag[k]=0;
        q.pop();
        for (int i=first[k];i;i=a[i].next)
        if (dis[a[i].son]<dis[k]+a[i].v)
        {
            dis[a[i].son]=dis[k]+a[i].v;
            if (!flag[a[i].son])
            {
                flag[a[i].son]=1; 
                num[a[i].son]++;
                if (num[a[i].son]>=n) printf("-1"),exit(0);
                q.push(a[i].son);
            }
        }
    }   
    for (int i=1;i<=n;i++) ans+=dis[i];
    printf("%lld",ans);
}

你可能感兴趣的:(【BZOJ2330】【tyvj1785】【codevs2404】糖果,第一次的差分约束)