1. 程式人生 > >【Bzoj2330】【Scoi2011】糖果

【Bzoj2330】【Scoi2011】糖果

int iostream efi bzoj data spfa ace www -1

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=2330

這是一道比較裸的差分約束,這裏求的是最小值,

建立一個超級原點0,跑spfa。

主要的點都在程序中,但是有幾個註意點:

1.這裏求的是最長路,可以 把邊權都取負,就可以跑最短路,最後答案取負就可以了。

2.spfa判負環的時候,因為增加了一個超級原點,所以需要cnt[x]>=n+1才可以判定存在復還負環。

上程序:

1 #include<iostream>

2 #include<algorithm>

3 #include<queue>

4 #include<vector>

5 #define ll long long

6 using namespace std;

7 const int maxn=100007;

8 const ll inf=1LL<<29;

9 struct data{

10 int to,val;

11 };

12 vector <data> a[maxn];

13 int n,k,x,p,q;

14 ll ans=0,dis[maxn];

15 int cnt[maxn];

16 bool inq[maxn];

17 queue <int> que;

18 void add(int u,int v,int w){

19 data tmp;

20 tmp.to=v; tmp.val=w;

21 a[u].push_back(tmp);

22 }

23 bool spfa(int s){

24 que.push(0);

25 inq[0]=true;

26 cnt[0]=1;

27 dis[0]=0;

28 while (!que.empty()) {

29 int now=que.front();

30 que.pop();

31 inq[now]=false;

32 for (int i=0; i<a[now].size(); i++) {

33 int vv=a[now][i].to; int ww=a[now][i].val;

34 if (dis[now]+ww<dis[vv]) {

35 dis[vv]=dis[now]+ww;

36 if (!inq[vv]) {

37 que.push(vv);

38 inq[vv]=true;

39 ++cnt[vv];

40 if (cnt[vv]>n) return false;

41 }

42 }

43 }

44 }

45 return true;

46 }

47 int main(){

48 ios::sync_with_stdio(false);

49 cin>>n>>k;

50 fill(inq,inq+maxn,false);

51 fill(dis,dis+maxn,inf);

52 for (int i=1; i<=k; i++) {

53 cin>>x>>p>>q;

54 if (x==1) add(p,q,0),add(q,p,0);

55 if (x==2) add(p,q,-1);

56 if (x==3) add(q,p,0);

57 if (x==4) add(q,p,-1);

58 if (x==5) add(p,q,0);

59 }

60 for (int i=1; i<=n; i++) add(0,i,-1);

61 if (!spfa(0)) cout<<"-1"<<endl;

62 else {

63 for (int i=1; i<=n; i++) ans+=dis[i];

64 ans*=(-1);

65 cout<<ans<<endl;

66 }

67 return 0;

68 }

【Bzoj2330】【Scoi2011】糖果