BZOJ2330_糖果_KEY
看题目可知这是一道差分约束的题目。
根据每种关系建边如下:
对于每种情况建边,然后跑一边SPFA。(最长路)
因为可能会有自环或环的情况,都不可能存在。
跑SPFA时记录入队次数,超过N弹出。
SPFA的dist起始值为1,ans=∑dist[i]
对于每个点做一遍SPFA会超时,所以将所有点放入队列中,所有点一起跑SPFA。
code:
/************************************************************** Problem: 2330 User: yekehe Language: C++ Result: Accepted Time:1280 ms Memory:43792 kb ****************************************************************/ #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; int read() { char c;while(c=getchar(),(c<'0'||c>'9')&&c!='-'); int x=0,y=1;c=='-'?y=-1:x=c-'0'; while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0'; return x*y; } struct list{ int head[100005],nxt[200005],To[200005],W[200005],cnt; list(){ memset(head,-1,sizeof head); memset(nxt,-1,sizeof nxt); cnt=0; } void add(int x,int y,int c) { To[cnt]=y; W[cnt]=c; nxt[cnt]=head[x]; head[x]=cnt; cnt++; } }P; int N,K; int dist[100005],l[10000000],flag[100005]; int into[100005],SF=0; void SPFA() { int h=0,t=0; memset(into,0,sizeof into); for(int i=1;i<=N;i++)l[++t]=i,into[i]++;//入队++ while(h<t){ int front=l[++h]; flag[front]=0; for(int i=P.head[front];i!=-1;i=P.nxt[i]){ if(dist[P.To[i]]<P.W[i]+dist[front]){//求最长路 dist[P.To[i]]=P.W[i]+dist[front]; if(!flag[P.To[i]]){ l[++t]=P.To[i],flag[P.To[i]]=1; into[P.To[i]]++; if(into[P.To[i]]>N){SF=-1;return ;}//判环 } } } } return ; } int main() { N=read();K=read(); register int i; for(i=1;i<=K;i++){ int o=read(),x=read(),y=read(); switch(o){ case 1:P.add(x,y,0),P.add(y,x,0);break; case 2:P.add(x,y,1);break; case 3:P.add(y,x,0);break; case 4:P.add(y,x,1);break; case 5:P.add(x,y,0);break; } } for(i=1;i<=N;i++)dist[i]=1; SPFA(); if(SF<0)return puts("-1"),0;//有环 long long ans=0; for(i=1;i<=N;i++)ans+=(long long)dist[i]; printf("%lld",ans); return 0; }