【洛谷 P3385】模板-负环(图论--spfa)

题目:有一个图有N个顶点,M条边。边用三个整数a b w表示,意思为a->b有一条权值为w的边(若w<0则为单向,否则双向)。共T组数据。对于每组数据,存在负环则输出一行"YE5"(不含引号),否则输出一行"N0"(不含引号)。

注意——坑爹的输出啊!!它不是平常的 YES 和 NO!!

解法:1.spfa_bfs,判断结点入队超过 n 次就出现负环。最差的情况是O(nm)。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<queue>
 6 using namespace std;
 7 
 8 const int N=200010;
 9 struct edge{int x,y,d,next;}a[N*2];
10 int last[N],vis[N],cnt[N],d[N];
11 int len,n,m;
12 queue<int> q;
13 
14 void ins(int x,int y,int d)
15 {
16     a[++len].x=x,a[len].y=y,a[len].d=d;
17     a[len].next=last[x],last[x]=len;
18 }
19 bool spfa()
20 {
21     while (!q.empty()) q.pop();
22     memset(d,63,sizeof(d));
23     memset(cnt,0,sizeof(cnt));
24     memset(vis,0,sizeof(vis));
25     d[1]=0,vis[1]=1,cnt[1]++;
26     q.push(1);
27     while (!q.empty())
28     {
29       int x=q.front();
30       q.pop(); vis[x]=0;//此处无cnt++
31       for (int i=last[x];i!=-1;i=a[i].next)
32       {
33         int y=a[i].y;
34         if (d[x]+a[i].d<d[y])
35         {
36           d[y]=d[x]+a[i].d;
37           if (!vis[y])
38           {
39             q.push(y);
40             vis[y]=1, cnt[y]++;
41             if (cnt[y]>n) return true;
42           }
43         }
44       }
45     }
46     return false;
47 }
48 int main()
49 {
50     int T;
51     scanf("%d",&T);
52     while (T--)
53     {
54       scanf("%d%d",&n,&m);
55       int x,y,d; len=0;
56       memset(last,-1,sizeof(last));
57       for (int i=1;i<=m;i++)
58       {
59         scanf("%d%d%d",&x,&y,&d);
60         ins(x,y,d);
61         if (d>=0) ins(y,x,d);
62       }
63       if (spfa()) printf("YE5\n");
64       else printf("N0\n");
65     }
66     return 0;
67 }
bfs TLE

         2.spfa_dfs,枚举起点,找最短路,若再一次访问到已经访问过的结点就出现负环。最差的情况也是O(nm)。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 
 7 const int N=200010,INF=(int)1e9;
 8 struct edge{int x,y,d,next;}a[N*2];
 9 int last[N],vis[N],dis[N];
10 int len,n,m;
11 
12 void ins(int x,int y,int d)
13 {
14     a[++len].x=x,a[len].y=y,a[len].d=d;
15     a[len].next=last[x],last[x]=len;
16 }
17 bool dfs(int x)
18 {
19     if (vis[x]) return true;
20     vis[x]=1;
21     for (int i=last[x];i!=-1;i=a[i].next)
22     {
23       int y=a[i].y;
24       //if (y==fa) continue;//有dis的判断
25       if (dis[x]+a[i].d<dis[y])
26       {
27         dis[y]=dis[x]+a[i].d;
28         if (dfs(y)) return true;
29       }
30     }
31     vis[x]=0;//判断一个点是否在“同一”路径重复出现而已。
32     return false;//
33 }
34 int main()
35 {
36     int T;
37     scanf("%d",&T);
38     while (T--)
39     {
40       scanf("%d%d",&n,&m);
41       int x,y,d; len=0;
42       memset(last,-1,sizeof(last));
43       for (int i=1;i<=m;i++)
44       {
45         scanf("%d%d%d",&x,&y,&d);
46         ins(x,y,d);
47         if (d>=0) ins(y,x,d);
48       }
49       for (int i=1;i<=n;i++) dis[i]=INF;
50       memset(vis,0,sizeof(vis));
51       dis[1]=0;//起点不确定的!
52       if (dfs(1)) printf("YE5\n");
53       else printf("N0\n");
54     }
55     return 0;
56 }
dfs WA(起点不能只是随便定一个点)
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 typedef long long LL;
 7 
 8 const int N=200010,D=200010;
 9 const LL INF=(LL)5e10;
10 int n,m,len;
11 bool cir;
12 int last[N],vis[N];
13 LL dis[N];
14 struct edge{int x,y,next;LL d;}a[2*N];
15 
16 void ins(int x,int y,LL d)
17 {
18     a[++len].x=x,a[len].y=y,a[len].d=d;
19     a[len].next=last[x],last[x]=len;
20 }
21 void dfs(int x)
22 {
23     if (vis[x]) {cir=true;return;}
24     vis[x]=1;
25     for (int i=last[x];i;i=a[i].next)
26     {
27       int y=a[i].y;
28       if (dis[x]+a[i].d<dis[y])
29       {
30         dis[y]=dis[x]+a[i].d;
31         dfs(y);
32         if (cir) return;
33       }
34     }
35     vis[x]=0;
36 }
37 int main()
38 {
39     int T;
40     scanf("%d",&T);
41     while (T--)
42     {
43       int x,y; LL d;
44       len=0;
45       memset(last,0,sizeof(last));
46       scanf("%d%d",&n,&m);
47       for (int i=1;i<=m;i++)
48       {
49         scanf("%d%d%lld",&x,&y,&d);
50         ins(x,y,d);
51         if (d>=0) ins(y,x,d);
52       }
53       cir=false;
54       for (int i=1;i<=n;i++)
55       {
56         for (int j=1;j<=n;j++) dis[j]=INF;
57         memset(vis,0,sizeof(vis));
58         dis[i]=0, dfs(i);
59         if (cir) break;
60       }
61       if (cir) printf("YE5\n");
62       else printf("N0\n");
63     }
64     return 0;
65 }
dfs TLE

         3.spfa_dfs+优化,既然是找负环,那么就是找权和为负数的回路。P.S.这个一定要理解!!ヾ(。 ̄□ ̄)ツ゜゜゜我想了很久......网上也没搜到。负环负环,不单单是含负权边的环,而是权和为负的环。原因是对于一个在负环里的点,只有经过负环后的距离还比原来的小,才会再一次访问该点。要不怎么会一直循环走这个环,直到RE呢......ヘ(_ _ヘ) 也就是环的权和为负数!
     实现就是我们对 dis 数组清零,再权和为负的情况下做spfa,且使用 dfs 判断成环。时间复杂度远远小于O(nm)。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 typedef long long LL;
 7 
 8 const int N=200010,D=200010;
 9 const LL INF=(LL)5e10;
10 int n,m,len;
11 bool cir;
12 int last[N],vis[N];
13 LL dis[N];
14 struct edge{int x,y,next;LL d;}a[2*N];
15 
16 void ins(int x,int y,LL d)
17 {
18     a[++len].x=x,a[len].y=y,a[len].d=d;
19     a[len].next=last[x],last[x]=len;
20 }
21 void dfs(int x)
22 {
23     if (vis[x]) {cir=true;return;}
24     vis[x]=1;
25     for (int i=last[x];i;i=a[i].next)
26     {
27       int y=a[i].y;
28       if (dis[x]+a[i].d<dis[y])
29       {
30         dis[y]=dis[x]+a[i].d;
31         dfs(y);
32         if (cir) return;
33       }
34     }
35     vis[x]=0;
36 }
37 int main()
38 {
39     int T;
40     scanf("%d",&T);
41     while (T--)
42     {
43       int x,y; LL d;
44       len=0;
45       memset(last,0,sizeof(last));
46       scanf("%d%d",&n,&m);
47       for (int i=1;i<=m;i++)
48       {
49         scanf("%d%d%lld",&x,&y,&d);
50         ins(x,y,d);
51         if (d>=0) ins(y,x,d);
52       }
53       memset(dis,0,sizeof(dis));
54       memset(vis,0,sizeof(vis));
55       cir=false;
56       for (int i=1;i<=n;i++)
57       {
58         dfs(i);
59         if (cir) break;
60       }
61       if (cir) printf("YE5\n");
62       else printf("N0\n");
63     }
64     return 0;
65 }
dfs AC

 

转载于:https://www.cnblogs.com/konjak/p/6076308.html

一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图与注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值