BZOJ 2330 [SCOI2011]糖果

来源:互联网 发布:windows vue webpack 编辑:程序博客网 时间:2024/05/29 12:09

发现篇博文讲差分约束讲的挺好
http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html

照着文章自学了一遍,发现这道题就是一道裸题嘛。
设一个超级源,表示基础的0,要求所有的值均严格大于0,spfa一下,将距离数组相加就是答案,若存在负环,则不存在一个合理解。

关于差分约束的建图,还想mark一下:
1.若求一个变量xi满足xxians中ans的最小值,即xi最小比x大多少,变形为xans+xi,类似于单源最短路径的更新,则将有向图的边从x连向xi,求最短路;
2.若不等式形式为xxians,求ans最大值,则转化为最长路。
对于这道题的一个毒瘤数据:一条1->n的链,0向其他节点建边的顺序反向即可,从1更新到n,一次更新完毕,避免最坏退化成O(n2)

#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<queue>#include<algorithm>using namespace std;const int maxn=100005;struct edge{    int to,next,val;}e[maxn<<2];int n,m;int head[maxn],dist[maxn],tim[maxn];bool inq[maxn];void insert(int a,int b,int c){    static int cnt=0;    e[++cnt].to=b;e[cnt].val=c;e[cnt].next=head[a];head[a]=cnt;}bool spfa(){    queue<int>q;    q.push(0);inq[0]=1;    while(!q.empty())    {        int u=q.front();        q.pop();        inq[u]=false;        for(int i=head[u];i;i=e[i].next)        {            int v=e[i].to;            if(dist[u]+e[i].val>dist[v])            {                dist[v]=dist[u]+e[i].val;                tim[v]++;                if(tim[v]>n)return false;                if(inq[v])continue;                inq[v]=true,q.push(v);            }        }    }    return true;}int main(){    scanf("%d%d",&n,&m);    for(int i=n;i;i--)//倒着加边         insert(0,i,1);    for(int i=1,op,d1,d2;i<=m;i++)    {        scanf("%d%d%d",&op,&d1,&d2);        if(op%2==0&&d1==d2){puts("-1");return 0;}        if(op==1)insert(d1,d2,0),insert(d2,d1,0);        else if(op==2)insert(d1,d2,1);        else if(op==3)insert(d2,d1,0);        else if(op==4)insert(d2,d1,1);        else insert(d1,d2,0);    }    if(!spfa()){puts("-1");return 0;}    long long ans=0;    for(int i=1;i<=n;i++)        ans+=dist[i];    printf("%lld",ans);    return 0;} 
原创粉丝点击