BZOJ2330 [SCOI2011]糖果(洛谷P3275)

差分约束

BZOJ题目传送门
洛谷题目传送门

差分约束学了就没用过。。。现在忘光了
貌似这道题可以Tarjan+拓扑过,但是我不会

其实这道题是很裸的差分约束了。我们来分析一下这五种关系:

1:建 x y 的权值为 0 的双向边。
2:建 x y 的权值为 1 的单向边。注意当 x = y 时判掉
3:建 y x 的权值为 0 的单项边。
4:建 y x 的权值为 1 的单项边。注意当 x = y 时判掉
5:建 x y 的权值为 0 的单项边。

然后spfa跑最长路即可。
然而出题人出了一条链。。。那么一开始就把所有点加进去就行了。
注意判环,答案爆 i n t

代码:

#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define F inline
using namespace std;
typedef long long LL;
struct edge{ int nxt,to,d; }ed[N<<2];
int n,m,k,h[N],t[N],d[N];
LL ans; bool f[N];
queue <int> q;
F char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    return l==r?EOF:*l++;
}
F int _read(){
    int x=0; char ch=readc();
    while (!isdigit(ch)) ch=readc();
    while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
    return x;
}
#define addedge(x,y,z) (ed[++k]=(edge){h[x],y,z},h[x]=k)
F bool spfa(){
    while (!q.empty()){
        int x=q.front(); f[x]=false,q.pop();
        for (int i=h[x],v;i;i=ed[i].nxt)
            if (d[x]+ed[i].d>d[v=ed[i].to]){
                d[v]=d[x]+ed[i].d;
                if (++t[v]>=n) return false;
                if (!f[v]) q.push(v),f[v]=true;
            }
    }
    return true;
}
int main(){
    n=_read(),m=_read();
    for (int i=1;i<=m;i++){
        int f=_read(),x=_read(),y=_read();
        switch(f){
            case 1: addedge(x,y,0),addedge(y,x,0); break;
            case 3: addedge(y,x,0); break;
            case 5: addedge(x,y,0); break;
            default:
                if (x==y) return puts("-1"),0;
                f==2?addedge(x,y,1):addedge(y,x,1); break;
        }
    }
    for (int i=1;i<=n;i++) d[i]=t[i]=f[i]=true,q.push(i);
    if (!spfa()) return puts("-1"),0;
    for (int i=1;i<=n;i++) ans+=d[i];
    return printf("%lld\n",ans),0;
}

猜你喜欢

转载自blog.csdn.net/a1799342217/article/details/80889453