[BZOJ2330][SCOI2011]糖果(差分约束系统)

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2330


差分约束系统的裸题啊,十分推荐这篇blog http://blog.csdn.net/consciousman/article/details/53812818
大概的说一下原理就是把不等式组关系转化成图然后跑spfa通过spfa算法里面的“松弛”操作来求解不等式组。
那么了解了这个算法之后这道题就蛮简单的了,可以把五种操作分别对应的不等式列出来建边。
但是有许多的坑点。
第一:边目录的大小要开到N*4(这个应该是我失了智卡了好久)
第二:这个题目数据有一个是有一条长度为十万的链,直接spfa会T飞,有几种做法可以解决这个问题
1、如果直接建立边目录的话会超时,但是可以倒着建。这个是黄学长的玄学做法,应该是面向数据编程(雾
2、如果用spfa判环的话那就是一个点进栈超过n次就出现环了(这题有st就是n+1次),但是数据应该没有这么极端(笑)所以可以判断进栈超过n/k(1<=k<=10)就判环,可以节省时间,也是是面向数据编程(雾
3、比较正统的用强连通缩点做法可以看这篇 http://blog.csdn.net/Leo_h1104/article/details/74627137


code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100010;
struct node
{
    int x,y,c,next;
}a[maxn*5]; int len,last[maxn];
void ins(int x,int y,int c)
{
    len++;
    a[len].x=x;a[len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;
}
int st,ed;
long long d[maxn]; bool vis[maxn];
int list[maxn*2],head,tail;
int times[maxn];
int n,m;
queue<int> Q;
bool spfa()  
{  
    int i,t;  
    vis[0]=1;  
    Q.push(0);  
    while(!Q.empty())  
    {  
        t=Q.front();  
        Q.pop();  
        vis[t]=0;  
        for(i=last[t];i;i=a[i].next)  
        {  
            if(d[t]+a[i].c>d[a[i].y])  
            {  
                d[a[i].y]=d[t]+a[i].c;  
                if(++times[a[i].y]>n) return false;  
                if(!vis[a[i].y])   
                {  
                    vis[a[i].y]=1;  
                    Q.push(a[i].y);  
                }  
            }  
        }  
    }  
    return true;  
}  
; 
int main()  
{   
    scanf("%d%d",&n,&m);  
    len=0; memset(last,0,sizeof(last));
    for(int i=1;i<=m;i++)  
    {  
        int op,x,y;
        scanf("%d%d%d",&op,&x,&y);  
        if(op==1) ins(x,y,0),ins(y,x,0);  
        else if(op==2)   
        {  
            if(x==y)   
            {  
                printf("-1\n"); 
                return 0;  
            }   
            ins(x,y,1);  
        }  
        else if(op==3) ins(y,x,0);  
        else if(op==4)  
        {  
            if(x==y)   
            {  
                printf("-1\n");  
                return 0;  
            }  
            ins(y,x,1);  
        }   
        else if(op==5) ins(x,y,0);  
    }  
    for(int i=n;i>0;i--) ins(0,i,1);  
    long long ans=0;  
    if(!spfa())   
    {  
        printf("-1\n");  
        return 0;  
    }  
    for(int i=1;i<=n;i++) ans+=d[i];  
    printf("%lld\n",ans);  
    return 0;  
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值