【BZOJ2330】糖果(差分约束系统,强连通分量,拓扑排序)

题意:

幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww需要满足小朋友们的K个要求。幼儿园的糖果总是有限的,lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

输入的第一行是两个整数NK

接下来K行,表示这些点需要满足的关系,每行3个数字,XAB

如果X=1, 表示第A个小朋友分到的糖果必须和第B个小朋友分到的糖果一样多;

如果X=2, 表示第A个小朋友分到的糖果必须少于第B个小朋友分到的糖果;

如果X=3, 表示第A个小朋友分到的糖果必须不少于第B个小朋友分到的糖果;

如果X=4, 表示第A个小朋友分到的糖果必须多于第B个小朋友分到的糖果;

如果X=5, 表示第A个小朋友分到的糖果必须不多于第B个小朋友分到的糖果;

对于所有的数据,保证 N<=100000,K<=100000,1<=X<=5,1<=A, B<=N

思路:第一反应应该是差分约束系统,但N的范围令人不放心,实际上裸SPFA也需要一些优化才能跑过去

知乎上有几位大佬说这题是tarjan缩点+拓扑排序,确实这种做法理论复杂度才是有保证的

先建立原图,对于等于关系连双向边,小于等于(和大于等于,显然等价)连单向边,先缩一次点,同一个分量里的人糖果数一定相等

再进行拓扑排序计算每一个分量的糖果数,环会导致无解,注意糖果数和前面推导不同时需要取MAX

最后特判下同一个分量里的边有没有不等的,有则无解

SPFA

 1 var q:array[0..2000000]of longint;
 2     head,vet,next,len,dis,time:array[1..200000]of longint;
 3     inq:array[1..200000]of boolean;
 4     n,m,i,x,a,b,tot:longint;
 5     ans,tmp:int64;
 6  
 7 procedure add(a,b,c:longint);
 8 begin
 9  inc(tot);
10  next[tot]:=head[a];
11  vet[tot]:=b;
12  len[tot]:=c;
13  head[a]:=tot;
14 end;
15  
16 procedure spfa;
17 var t,w,i,u,e,v:longint;
18 begin
19  fillchar(time,sizeof(time),0);
20  t:=0; w:=-1;
21  for i:=1 to n do
22  begin
23   dis[i]:=1; inc(w); q[w]:=i; inq[i]:=true;
24  end;
25  
26  while t<=w do
27  begin
28   u:=q[t mod n]; inc(t); inq[u]:=false;
29   e:=head[u];
30   while e<>0 do
31   begin
32    v:=vet[e];
33    if dis[u]+len[e]>dis[v] then
34    begin
35     dis[v]:=dis[u]+len[e];
36     if not inq[v] then
37     begin
38      inc(time[v]);
39      if time[v]>n then
40      begin
41       writeln(-1); ans:=-1;
42       exit;
43      end;
44      inc(w); q[w mod n]:=v; inq[v]:=true;
45     end;
46    end;
47    e:=next[e];
48   end;
49  end;
50 end;
51  
52 begin
53   
54  read(n,m);
55  for i:=1 to m do
56  begin
57   read(x,a,b);
58   if (x and 1=0)and(a=b) then
59   begin
60    writeln(-1);
61    exit;
62   end;
63   case x of
64    1:begin add(b,a,0); add(a,b,0); end;
65    2:add(a,b,1);
66    3:add(b,a,0);
67    4:add(b,a,1);
68    5:add(a,b,0);
69   end;
70  end;
71  spfa;
72  if ans=0 then
73  begin
74   for i:=1 to n do ans:=ans+dis[i];
75  
76   writeln(ans);
77  end;
78   
79 end.

tarjan+拓扑排序

  1 #include<map> 
  2 #include<set>
  3 #include<cmath>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<cstring>
  7 #include<cstdlib>
  8 #include<iostream>
  9 #include<algorithm>
 10 #include<queue>
 11 using namespace std;
 12 const int M=210000;
 13 int head[M],vet[M],next[M],len[M],a[M],b[M],c[M],dfn[M],low[M],flag[M],ind[M],stack[M],s[M];
 14 int n,m,i,tot,id,top,cnt;
 15 long long d[M],size[M];
 16  
 17 void add(int a,int b,int c)
 18 {
 19   next[++tot]=head[a];
 20   vet[tot]=b;
 21   len[tot]=c;
 22   head[a]=tot;
 23   ind[b]++;
 24 }
 25  
 26 void swap(int &a,int &b)
 27 {
 28     int t;
 29     t=a;a=b;b=t;
 30 }
 31  
 32 void dfs(int u)
 33 {
 34     int e,v;
 35     flag[u]=1;
 36     stack[++top]=u;
 37     dfn[u]=low[u]=++cnt;
 38     for(e=head[u];e;e=next[e])
 39     {
 40         v=vet[e];
 41         if(!flag[v])
 42         {
 43             dfs(v);
 44             low[u]=min(low[u],low[v]);
 45         }
 46          else if(!s[v]) low[u]=min(low[u],low[v]);
 47     }
 48     if(low[u]==dfn[u])
 49     {
 50         id++; 
 51         while(stack[top]!=u)
 52         {
 53             s[stack[top]]=id; 
 54             size[id]++;
 55             top--;
 56         }
 57         s[stack[top]]=id; 
 58         size[id]++;
 59         top--;
 60     }
 61      
 62 }
 63  
 64 long long solve()
 65 {
 66     queue<int> q;
 67     int num;
 68     long long sum;
 69     for(int i=1;i<=id;i++)
 70      if(!ind[i]) 
 71      {
 72        q.push(i);
 73        d[i]=1;
 74      } 
 75     if(q.empty()) return -1;
 76     num=0;
 77     while(!q.empty())
 78     {
 79         int u=q.front(); q.pop(); num++;
 80         for(int e=head[u];e;e=next[e])
 81         {
 82             int v=vet[e];
 83             ind[v]--;
 84             d[v]=max(d[v],d[u]+len[e]);
 85             if(!ind[v]) q.push(v);
 86         }
 87     }
 88     if(num<id) return -1;
 89      else 
 90      {
 91         sum=0;
 92         for(int i=1;i<=id;i++) sum=sum+d[i]*size[i];
 93         return sum;
 94      }
 95      
 96 }
 97  
 98 int main()
 99 {
100    // freopen("bzoj2330.in","r",stdin);
101    // freopen("bzoj2330.out","w",stdout);
102     scanf("%d%d",&n,&m);
103     id=0;
104     for(i=1;i<=m;i++)
105     {
106         scanf("%d%d%d",&a[i],&b[i],&c[i]);
107         if(a[i]==3||a[i]==4) swap(b[i],c[i]);
108         if(a[i]==1)
109         {
110             add(b[i],c[i],0);
111             add(c[i],b[i],0);
112         }
113         if(a[i]==3||a[i]==5) add(b[i],c[i],0);
114     }
115     for(i=1;i<=n;i++)
116      if(!flag[i]) dfs(i);
117     //printf("%d\n",id);
118     memset(head,0,sizeof(head));
119     memset(ind,0,sizeof(ind));
120     tot=0;
121     for(i=1;i<=m;i++)
122      if(s[b[i]]!=s[c[i]])
123      {
124         if(a[i]==3||a[i]==5) add(s[b[i]],s[c[i]],0); 
125          else add(s[b[i]],s[c[i]],1); 
126      }
127       else
128       {
129         if(a[i]==2||a[i]==4) 
130         {
131           printf("-1\n");
132           return 0;
133         }   
134       }
135  printf("%lld\n",solve());
136  return 0;  
137 }

 

 

 

posted on 2018-07-04 19:20  myx12345  阅读(284)  评论(0编辑  收藏  举报

导航