bzoj:2330 [SCOI2011]糖果
阿新 • • 發佈:2018-12-11
演算法:差分約束+spfa最長路
難度:NOIP
很容易看出來這道題是差分約束,對於本題來說,因為至少一個糖果,所以add(0,i,1) 注意陣列大小!!!
一次SPFA之後,直接輸出dis陣列總和,即為總糖果數。
注意:
1、判斷自環
2、不開long long見祖宗
3、陣列大小!!!
程式碼如下:
#include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> #include <algorithm> #include <cmath> #include <deque> #define ll long long #define N 100005 using namespace std; struct node { int next; int to; int val; }edge[N<<2];//下面還有n條邊啊啊啊 int head[N],cir[N]; bool vis[N]; int cnt=1; void init() { memset(head,-1,sizeof(head)); cnt=1; } void add(int u,int v,int w) { edge[cnt].next=head[u]; edge[cnt].to=v; edge[cnt].val=w; head[u]=cnt++; } int dis[N]; int n,k; bool spfa(int rt) { //memset(dis,0,sizeof(dis));多清陣列會導致TLE deque<int>Q; vis[rt]=1; dis[rt]=0; cir[rt]=1; Q.push_back(rt); while(!Q.empty()) { int u=Q.front(); Q.pop_front(); for(int i = head[u];i!=-1;i=edge[i].next) { int to=edge[i].to; if(dis[to]<dis[u]+edge[i].val) { dis[to]=dis[u]+edge[i].val; if(++cir[to]>n) //如果沒有環,不可能有某個點dis大於n,若大於n則必有環 { return 0; } if(!vis[to]) { vis[to]=1; if(!Q.empty()&&dis[to]>dis[Q.front()]) { Q.push_front(to); }else { Q.push_back(to); } } } } vis[u]=0; } return 1; } void read(int &x) { int f=1;x=0;char s=getchar(); while(s<'0'||s>'9') s=getchar(); while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} x*=f; } int main() { scanf("%d%d",&n,&k); //read(n),read(k); init(); for(int i = 1;i <= k;i++) { int x,a,b; //scanf("%d%d%d",&x,&a,&b); read(x),read(a),read(b); if((x%2==0)&&(a==b))//注意判斷自環 { puts("-1"); return 0 ; } if(x==1) { add(a,b,0); add(b,a,0); }else if(x==2) { add(a,b,1); }else if(x==3) { add(b,a,0); }else if(x==4) { add(b,a,1); }else if(x==5) { add(a,b,0); } } for(int i = n;i >= 1;i--) add(0,i,1);//為什麼倒著加邊就能A??? ll ans=0; if(!spfa(0)) { puts("-1"); return 0 ; }else { for(int i = 1;i <= n;i++)ans += dis[i]; //dis[i]是第i個小朋友最少需要的糖果數量 printf("%lld\n",ans); } return 0 ; }