递归型SPFA+二分答案 || 负环 || BZOJ 4773

题解:

基本思路是二分答案,每次用Dfs型SPFA验证该答案是否合法。

一点细节我注释在代码里了。

代码:

 

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 inline int rd(){
 5     int x=0,f=1; char c=getchar();
 6     while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
 7     while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
 8     return f*x;
 9 }
10 const int maxn=305,maxm=305*305,inf=(1<<30)-5;
11 int N,M,edge_head[maxn],num_edge=0,u,v,w,Dis[maxn];
12 bool vis[maxn],flag;
13 struct Edge{ int to,nx,dis; }edge[maxm];
14 inline void Add_edge(int from,int to,int dis){
15     edge[++num_edge].nx=edge_head[from];
16     edge[num_edge].to=to;
17     edge[num_edge].dis=dis;
18     edge_head[from]=num_edge;
19     return;
20 }
21 inline void SPFA(int x,int now,int Limit){
22 //判断是否存在当前位于x,现在已经用了now个点,点数不超过Limit的负环
23     if(flag) return;
24     for(int i=edge_head[x];i;i=edge[i].nx){
25         int y=edge[i].to;
26         if(Dis[y]>=Dis[x]+edge[i].dis){
27             if(vis[y]){
28                 flag=1;
29                 return;
30             } 
31             else if(now+1<=Limit){
32                 vis[y]=1;
33                 Dis[y]=Dis[x]+edge[i].dis;
34                 SPFA(y,now+1,Limit);
35                 vis[y]=0;
36                 //这里的Dis[y]不用回溯,其实是一种剪枝 
37             }
38         }
39     }
40     return;
41 }
42 int main(){
43     N=rd(); M=rd();
44     for(int i=1;i<=M;i++){
45         u=rd(); v=rd(); w=rd();
46         Add_edge(u,v,w);
47     }
48     
49     flag=0;
50     for(int i=1;i<=N;i++){    
51         memset(vis,0,sizeof(vis));
52         memset(Dis,0,sizeof(Dis));
53         vis[i]=1;
54         SPFA(i,1,N);
55         if(flag) break;
56     }
57     if(flag==0){
58         printf("0\n");
59         return 0;
60     }
61     
62     int l=2,r=N;
63     while(l<=r){
64         int mid=(l+r)>>1;
65         flag=0;
66         for(int i=1;i<=N;i++){                
67             memset(vis,0,sizeof(vis));
68             memset(Dis,0,sizeof(Dis));
69             vis[i]=1;
70             SPFA(i,1,mid);
71             if(flag){
72                 r=mid-1;
73                 break;
74             }
75         }
76         if(!flag) l=mid+1;
77     }
78     printf("%d\n",l);
79     return 0;
80 }
View Code

 


By:AlenaNuna

 

posted @ 2019-10-17 21:05  AlenaNuna  阅读(73)  评论(0编辑  收藏